diff --git a/api/client.go b/api/client.go
index 17ea0a289479a309311e9b8e721b91bedf87733d..a9e632ee8c20b3ade858d47fd33f30c658e3e0f4 100644
--- a/api/client.go
+++ b/api/client.go
@@ -13,12 +13,12 @@ import (
 	jww "github.com/spf13/jwalterweatherman"
 	"gitlab.com/elixxir/client/auth"
 	"gitlab.com/elixxir/client/catalog"
+	keyExchange2 "gitlab.com/elixxir/client/e2e/rekey"
 	"gitlab.com/elixxir/client/event"
 	"gitlab.com/elixxir/client/interfaces"
 	"gitlab.com/elixxir/client/interfaces/params"
 	"gitlab.com/elixxir/client/interfaces/preimage"
 	"gitlab.com/elixxir/client/interfaces/user"
-	"gitlab.com/elixxir/client/keyExchange"
 	"gitlab.com/elixxir/client/network"
 	"gitlab.com/elixxir/client/registration"
 	"gitlab.com/elixxir/client/stoppable"
@@ -564,7 +564,7 @@ func (c *Client) registerFollower() error {
 
 	//register the key exchange service
 	keyXchange := func() (stoppable.Stoppable, error) {
-		return keyExchange.Start(c.switchboard, c.storage, c.network, c.parameters.Rekey)
+		return keyExchange2.Start(c.switchboard, c.storage, c.network, c.parameters.Rekey)
 	}
 	err = c.followerServices.add(keyXchange)
 
diff --git a/e2e/manager.go b/e2e/manager.go
index 5871e7b069eed49e2db4584c6998d44b8239256e..f29c60f72f0bf52029d0e0cace409c909070271c 100644
--- a/e2e/manager.go
+++ b/e2e/manager.go
@@ -4,9 +4,11 @@ import (
 	"gitlab.com/elixxir/client/e2e/parse"
 	"gitlab.com/elixxir/client/e2e/ratchet"
 	"gitlab.com/elixxir/client/e2e/receive"
+	"gitlab.com/elixxir/client/event"
 	"gitlab.com/elixxir/client/network"
 	"gitlab.com/elixxir/client/storage/versioned"
 	"gitlab.com/elixxir/crypto/cyclic"
+	"gitlab.com/elixxir/crypto/fastRNG"
 	"gitlab.com/xx_network/primitives/id"
 )
 
@@ -16,8 +18,32 @@ type Manager struct {
 	partitioner parse.Partitioner
 	net         network.Manager
 	myID        *id.ID
+	rng         *fastRNG.StreamGenerator
+	events      event.Manager
+	grp         *cyclic.Group
 }
 
-func InitManager(kv *versioned.KV, myID *id.ID, privKey *cyclic.Int) {
+//Init Creates stores. After calling, use load
+func Init(kv *versioned.KV, myID *id.ID, privKey *cyclic.Int, grp *cyclic.Group) error {
+	return ratchet.New(kv, myID, privKey, grp)
+}
 
+// Load returns an e2e manager from storage
+func Load(kv *versioned.KV, net network.Manager, myID *id.ID,
+	grp *cyclic.Group, rng *fastRNG.StreamGenerator, events event.Manager) (*Manager, error) {
+	m := &Manager{
+		Switchboard: receive.New(),
+		partitioner: parse.NewPartitioner(kv, net.GetMaxMessageLength()),
+		net:         net,
+		myID:        myID,
+		events:      events,
+		grp:         grp,
+	}
+	var err error
+	m.Ratchet, err = ratchet.Load(kv, myID, grp,
+		&fpGenerator{m}, net, rng)
+	if err != nil {
+		return nil, err
+	}
+	return m, nil
 }
diff --git a/e2e/params.go b/e2e/params.go
new file mode 100644
index 0000000000000000000000000000000000000000..f897548a94ec04ceff08e985e1f7eb31db7b11c3
--- /dev/null
+++ b/e2e/params.go
@@ -0,0 +1,60 @@
+package e2e
+
+import (
+	"encoding/json"
+	"gitlab.com/elixxir/client/catalog"
+	"gitlab.com/elixxir/client/network"
+	"time"
+)
+
+type Params struct {
+	// Tag to use to generate the service.
+	ServiceTag string
+	// Often, for notifications purposes, all messages except the last should
+	// use a silent service. This allows a
+	LastServiceTag string
+
+	// The parameters adjust how the code behaves if there are not keys available.
+	// the number of times the code will attempt to get a key to encrypt with
+	KeyGetRetryCount uint
+	// Delay between attempting to get kets
+	KeyGeRetryDelay time.Duration
+
+	//Underlying cmix tags.
+	// Note: if critical is true, an alternative critical messages system within
+	// e2e will be used which preserves privacy
+	CMIX network.CMIXParams
+
+	//Authorizes the message to use a key reserved for rekeying. Do not use
+	//unless sending a rekey
+	Rekey bool
+}
+
+func GetDefaultParams() Params {
+	return Params{
+		ServiceTag:     catalog.Silent,
+		LastServiceTag: catalog.E2e,
+
+		KeyGetRetryCount: 10,
+		KeyGeRetryDelay:  500 * time.Millisecond,
+
+		CMIX:  network.GetDefaultCMIXParams(),
+		Rekey: false,
+	}
+}
+func (e Params) Marshal() ([]byte, error) {
+	return json.Marshal(e)
+}
+
+// GetParameters Obtain default E2E parameters, or override with
+// given parameters if set
+func GetParameters(params string) (Params, error) {
+	p := GetDefaultParams()
+	if len(params) > 0 {
+		err := json.Unmarshal([]byte(params), &p)
+		if err != nil {
+			return Params{}, err
+		}
+	}
+	return p, nil
+}
diff --git a/e2e/parse/partition.go b/e2e/parse/partition.go
index 06e10bcae00615e356ad305d4fef8d5ae5a38e4e..cb72eec3ea06f488169341c371277ad60803d5f0 100644
--- a/e2e/parse/partition.go
+++ b/e2e/parse/partition.go
@@ -31,7 +31,7 @@ type Partitioner struct {
 	partition         *partition.Store
 }
 
-func NewPartitioner(messageSize int, kv *versioned.KV) Partitioner {
+func NewPartitioner(kv *versioned.KV, messageSize int) Partitioner {
 	p := Partitioner{
 		baseMessageSize:   messageSize,
 		firstContentsSize: messageSize - firstHeaderLen,
diff --git a/e2e/processor.go b/e2e/processor.go
index e86e1a20bd8e86b649637ff172274107898eaf67..04c6b68a9e37d0b36bd9b6d4de7d36d907985ee7 100644
--- a/e2e/processor.go
+++ b/e2e/processor.go
@@ -19,7 +19,7 @@ func (p *processor) Process(ecrMsg format.Message, receptionID receptionID.Ephem
 	defer p.cy.Use()
 
 	//decrypt
-	msg, err := p.cy.Decrypt(ecrMsg)
+	contents, err := p.cy.Decrypt(ecrMsg)
 	if err != nil {
 		jww.ERROR.Printf("Decryption Failed of %s (fp: %s), dropping: %+v",
 			ecrMsg.Digest(), p.cy.Fingerprint(), err)
@@ -29,7 +29,7 @@ func (p *processor) Process(ecrMsg format.Message, receptionID receptionID.Ephem
 	//Parse
 	sess := p.cy.GetSession()
 	message, done := p.m.partitioner.HandlePartition(sess.GetPartner(),
-		msg.GetContents(), sess.GetRelationshipFingerprint())
+		contents, sess.GetRelationshipFingerprint())
 
 	if done {
 		message.RecipientID = receptionID.Source
diff --git a/e2e/ratchet/partner/session/cypher.go b/e2e/ratchet/partner/session/cypher.go
index 5a8f352b9147ca6bfefd09e6309a3ae8bf9107c6..fe713eb08c2cf07f563e9ebcfee80b8f0e94c5e2 100644
--- a/e2e/ratchet/partner/session/cypher.go
+++ b/e2e/ratchet/partner/session/cypher.go
@@ -86,45 +86,37 @@ func (k *Cypher) Fingerprint() format.Fingerprint {
 // the E2E key to encrypt msg to its intended recipient
 // It also properly populates the associated data, including the MAC, fingerprint,
 // and encrypted timestamp
-func (k *Cypher) Encrypt(msg format.Message) format.Message {
+func (k *Cypher) Encrypt(contents []byte) (ecrContents, mac []byte) {
 	fp := k.Fingerprint()
 	key := k.generateKey()
 
-	// set the fingerprint
-	msg.SetKeyFP(fp)
-
 	// encrypt the payload
-	encPayload := e2eCrypto.Crypt(key, fp, msg.GetContents())
-	msg.SetContents(encPayload)
+	ecrContents = e2eCrypto.Crypt(key, fp, contents)
 
 	// create the MAC
 	// MAC is HMAC(key, ciphertext)
 	// Currently, the MAC doesn't include any of the associated data
-	MAC := hash.CreateHMAC(encPayload, key[:])
-	msg.SetMac(MAC)
+	mac = hash.CreateHMAC(ecrContents, key[:])
 
-	return msg
+	return ecrContents, mac
 }
 
 // Decrypt uses the E2E key to decrypt the message
 // It returns an error in case of HMAC verification failure
 // or in case of a decryption error (related to padding)
-func (k *Cypher) Decrypt(msg format.Message) (format.Message, error) {
+func (k *Cypher) Decrypt(msg format.Message) ([]byte, error) {
 	fp := k.Fingerprint()
 	key := k.generateKey()
 
 	// Verify the MAC is correct
 	if !hash.VerifyHMAC(msg.GetContents(), msg.GetMac(), key[:]) {
-		return format.Message{}, errors.New("HMAC verification failed for E2E message")
+		return nil, errors.New("HMAC verification failed for E2E message")
 	}
 
 	// Decrypt the payload
 	decryptedPayload := e2eCrypto.Crypt(key, fp, msg.GetContents())
 
-	//put the decrypted payload back in the message
-	msg.SetContents(decryptedPayload)
-
-	return msg, nil
+	return decryptedPayload, nil
 }
 
 // Use sets the key as used. It cannot be used again.
diff --git a/e2e/ratchet/store.go b/e2e/ratchet/store.go
index 0cf1ca902210122ab812113ddc3a7c28c57f6570..b300a7c4453ed782b10de3c9f4c3ccc45ec295fc 100644
--- a/e2e/ratchet/store.go
+++ b/e2e/ratchet/store.go
@@ -55,13 +55,12 @@ type Ratchet struct {
 	kv *versioned.KV
 }
 
-// NewRatchet creates a new store for the passed user id and private key.
+// New creates a new store for the passed user id and private key.
 // The store can then be accessed by calling LoadStore.
 // Does not create at a unique prefix, if multiple Ratchets are needed, make
 // sure to add a uint prefix to the KV before instantiation.
-func NewRatchet(kv *versioned.KV, privKey *cyclic.Int,
-	myID *id.ID, grp *cyclic.Group, cyHandler session.CypherHandler,
-	services Services, rng *fastRNG.StreamGenerator) error {
+func New(kv *versioned.KV, myID *id.ID, privKey *cyclic.Int,
+	grp *cyclic.Group) error {
 
 	// Generate public key
 	pubKey := diffieHellman.GeneratePublicKey(privKey, grp)
@@ -79,10 +78,7 @@ func NewRatchet(kv *versioned.KV, privKey *cyclic.Int,
 
 		kv: kv,
 
-		cyHandler: cyHandler,
-		grp:       grp,
-		rng:       rng,
-		sInteface: services,
+		grp: grp,
 	}
 
 	err := util.StoreCyclicKey(kv, pubKey, pubKeyKey)
@@ -100,8 +96,8 @@ func NewRatchet(kv *versioned.KV, privKey *cyclic.Int,
 	return r.save()
 }
 
-// LoadRatchet loads an extant ratchet from disk
-func LoadRatchet(kv *versioned.KV, myID *id.ID, grp *cyclic.Group,
+// Load loads an extant ratchet from disk
+func Load(kv *versioned.KV, myID *id.ID, grp *cyclic.Group,
 	cyHandler session.CypherHandler, services Services, rng *fastRNG.StreamGenerator) (
 	*Ratchet, error) {
 	kv = kv.Prefix(packagePrefix)
diff --git a/keyExchange/confirm.go b/e2e/rekey/confirm.go
similarity index 88%
rename from keyExchange/confirm.go
rename to e2e/rekey/confirm.go
index 3ff7e3183b279de0cebef1071a662f094e29de96..a8d79136355be9077a8869c61ef7e05ab425e440 100644
--- a/keyExchange/confirm.go
+++ b/e2e/rekey/confirm.go
@@ -5,19 +5,19 @@
 // LICENSE file                                                              //
 ///////////////////////////////////////////////////////////////////////////////
 
-package keyExchange
+package rekey
 
 import (
 	"github.com/golang/protobuf/proto"
 	"github.com/pkg/errors"
 	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/e2e/ratchet"
 	session2 "gitlab.com/elixxir/client/e2e/ratchet/partner/session"
-	"gitlab.com/elixxir/client/interfaces/message"
+	"gitlab.com/elixxir/client/e2e/receive"
 	"gitlab.com/elixxir/client/stoppable"
-	"gitlab.com/elixxir/client/storage"
 )
 
-func startConfirm(sess *storage.Session, c chan message.Receive,
+func startConfirm(ratchet *ratchet.Ratchet, c chan receive.Message,
 	stop *stoppable.Single, cleanup func()) {
 	for true {
 		select {
@@ -26,14 +26,14 @@ func startConfirm(sess *storage.Session, c chan message.Receive,
 			stop.ToStopped()
 			return
 		case confirmation := <-c:
-			handleConfirm(sess, confirmation)
+			handleConfirm(ratchet, confirmation)
 		}
 	}
 }
 
-func handleConfirm(sess *storage.Session, confirmation message.Receive) {
+func handleConfirm(ratchet *ratchet.Ratchet, confirmation receive.Message) {
 	//ensure the message was encrypted properly
-	if confirmation.Encryption != message.E2E {
+	if !confirmation.Encrypted {
 		jww.ERROR.Printf(
 			"[REKEY] Received non-e2e encrypted Key Exchange "+
 				"confirm from partner %s", confirmation.Sender)
@@ -41,7 +41,7 @@ func handleConfirm(sess *storage.Session, confirmation message.Receive) {
 	}
 
 	//get the partner
-	partner, err := sess.E2e().GetPartner(confirmation.Sender)
+	partner, err := ratchet.GetPartner(confirmation.Sender)
 	if err != nil {
 		jww.ERROR.Printf(
 			"[REKEY] Received Key Exchange Confirmation with unknown "+
diff --git a/keyExchange/confirm_test.go b/e2e/rekey/confirm_test.go
similarity index 99%
rename from keyExchange/confirm_test.go
rename to e2e/rekey/confirm_test.go
index 87c453093c6c0cdb0fb3d6d0d378441fbdf753bf..1d47e0d69cb138cd894864971fd356d0de113bc2 100644
--- a/keyExchange/confirm_test.go
+++ b/e2e/rekey/confirm_test.go
@@ -5,7 +5,7 @@
 // LICENSE file                                                              //
 ///////////////////////////////////////////////////////////////////////////////
 
-package keyExchange
+package rekey
 
 import (
 	"github.com/cloudflare/circl/dh/sidh"
diff --git a/keyExchange/exchange.go b/e2e/rekey/exchange.go
similarity index 93%
rename from keyExchange/exchange.go
rename to e2e/rekey/exchange.go
index 121d3b2b4e0853d96a3509a188fe5da56e264179..620d6308736ea937edf21ae56a9ce2228e297d51 100644
--- a/keyExchange/exchange.go
+++ b/e2e/rekey/exchange.go
@@ -5,9 +5,10 @@
 // LICENSE file                                                              //
 ///////////////////////////////////////////////////////////////////////////////
 
-package keyExchange
+package rekey
 
 import (
+	"gitlab.com/elixxir/client/e2e/receive"
 	"gitlab.com/elixxir/client/interfaces"
 	"gitlab.com/elixxir/client/interfaces/message"
 	"gitlab.com/elixxir/client/interfaces/params"
@@ -21,7 +22,7 @@ const keyExchangeTriggerName = "KeyExchangeTrigger"
 const keyExchangeConfirmName = "KeyExchangeConfirm"
 const keyExchangeMulti = "KeyExchange"
 
-func Start(switchboard *switchboard.Switchboard, sess *storage.Session, net interfaces.NetworkManager,
+func Start(switchboard *receive.Switchboard, sess *storage.Session, net interfaces.NetworkManager,
 	params params.Rekey) (stoppable.Stoppable, error) {
 
 	// register the rekey trigger thread
diff --git a/keyExchange/exchange_test.go b/e2e/rekey/exchange_test.go
similarity index 99%
rename from keyExchange/exchange_test.go
rename to e2e/rekey/exchange_test.go
index 04d6c4ec205d5396fab1e29dd5b64540425fa547..4851e17d3edc6ef23f44ae1c49705df65cc3c44c 100644
--- a/keyExchange/exchange_test.go
+++ b/e2e/rekey/exchange_test.go
@@ -5,7 +5,7 @@
 // LICENSE file                                                              //
 ///////////////////////////////////////////////////////////////////////////////
 
-package keyExchange
+package rekey
 
 import (
 	"fmt"
diff --git a/keyExchange/generate.sh b/e2e/rekey/generate.sh
old mode 100755
new mode 100644
similarity index 100%
rename from keyExchange/generate.sh
rename to e2e/rekey/generate.sh
diff --git a/keyExchange/rekey.go b/e2e/rekey/rekey.go
similarity index 99%
rename from keyExchange/rekey.go
rename to e2e/rekey/rekey.go
index e76f54652cf58f9f1e9b0c0b5975c9d1eceb7a7d..888f85dad95716d9197ffb4e49dd61bc6c7961e1 100644
--- a/keyExchange/rekey.go
+++ b/e2e/rekey/rekey.go
@@ -5,7 +5,7 @@
 // LICENSE file                                                              //
 ///////////////////////////////////////////////////////////////////////////////
 
-package keyExchange
+package rekey
 
 import (
 	"fmt"
diff --git a/keyExchange/rekey_test.go b/e2e/rekey/rekey_test.go
similarity index 98%
rename from keyExchange/rekey_test.go
rename to e2e/rekey/rekey_test.go
index b507fc266803d597a6e39295911c3cb48894f263..6a07e438d95e3af31b598d58c86ee6a0b10b4d38 100644
--- a/keyExchange/rekey_test.go
+++ b/e2e/rekey/rekey_test.go
@@ -5,7 +5,7 @@
 // LICENSE file                                                              //
 ///////////////////////////////////////////////////////////////////////////////
 
-package keyExchange
+package rekey
 
 /*
 func TestRekey(t *testing.T) {
diff --git a/keyExchange/trigger.go b/e2e/rekey/trigger.go
similarity index 99%
rename from keyExchange/trigger.go
rename to e2e/rekey/trigger.go
index 85e68e48b2493e1131c5d1d09043a34f56b8770e..85011845f9f2db4fe17445b2f0c7324ee5af5043 100644
--- a/keyExchange/trigger.go
+++ b/e2e/rekey/trigger.go
@@ -5,7 +5,7 @@
 // LICENSE file                                                              //
 ///////////////////////////////////////////////////////////////////////////////
 
-package keyExchange
+package rekey
 
 import (
 	"fmt"
diff --git a/keyExchange/trigger_test.go b/e2e/rekey/trigger_test.go
similarity index 99%
rename from keyExchange/trigger_test.go
rename to e2e/rekey/trigger_test.go
index 6391fbab07cf54391c346f41162c42b556964583..2b568b2e29d6de6a0cd9abdab283a983a31c9449 100644
--- a/keyExchange/trigger_test.go
+++ b/e2e/rekey/trigger_test.go
@@ -5,7 +5,7 @@
 // LICENSE file                                                              //
 ///////////////////////////////////////////////////////////////////////////////
 
-package keyExchange
+package rekey
 
 import (
 	"github.com/cloudflare/circl/dh/sidh"
diff --git a/keyExchange/utils_test.go b/e2e/rekey/utils_test.go
similarity index 99%
rename from keyExchange/utils_test.go
rename to e2e/rekey/utils_test.go
index ed32032b4320569573019a3b74a6af65c218c652..2d4e7f7090fa2fcd65dd7f09f0fd3f8d93c3cb67 100644
--- a/keyExchange/utils_test.go
+++ b/e2e/rekey/utils_test.go
@@ -5,7 +5,7 @@
 // LICENSE file                                                              //
 ///////////////////////////////////////////////////////////////////////////////
 
-package keyExchange
+package rekey
 
 import (
 	"github.com/cloudflare/circl/dh/sidh"
diff --git a/keyExchange/xchange.pb.go b/e2e/rekey/xchange.pb.go
similarity index 99%
rename from keyExchange/xchange.pb.go
rename to e2e/rekey/xchange.pb.go
index 7871a130b05e6253843e73402d3d9f076d0b0189..a9b5f46ef0202e6b9e442b10f52c4298cf561489 100644
--- a/keyExchange/xchange.pb.go
+++ b/e2e/rekey/xchange.pb.go
@@ -13,7 +13,7 @@
 // 	protoc        v3.15.6
 // source: xchange.proto
 
-package keyExchange
+package rekey
 
 import (
 	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
diff --git a/keyExchange/xchange.proto b/e2e/rekey/xchange.proto
similarity index 100%
rename from keyExchange/xchange.proto
rename to e2e/rekey/xchange.proto
diff --git a/e2e/sendE2E.go b/e2e/sendE2E.go
new file mode 100644
index 0000000000000000000000000000000000000000..30acc83c9650b4a8b5d419368b4608604d6b467d
--- /dev/null
+++ b/e2e/sendE2E.go
@@ -0,0 +1,171 @@
+package e2e
+
+import (
+	"github.com/pkg/errors"
+	jww "github.com/spf13/jwalterweatherman"
+	"gitlab.com/elixxir/client/catalog"
+	"gitlab.com/elixxir/client/e2e/ratchet/partner/session"
+	keyExchange2 "gitlab.com/elixxir/client/e2e/rekey"
+	"gitlab.com/elixxir/client/network/message"
+	"gitlab.com/elixxir/client/stoppable"
+	"gitlab.com/elixxir/crypto/e2e"
+	"gitlab.com/elixxir/primitives/format"
+	"gitlab.com/xx_network/primitives/id"
+	"gitlab.com/xx_network/primitives/netTime"
+	"sync"
+	"time"
+)
+
+func (m *Manager) SendE2E(mt catalog.MessageType, recipient *id.ID,
+	payload []byte, params Params) ([]id.Round, e2e.MessageID, time.Time, error) {
+	//timestamp the message
+	ts := netTime.Now()
+
+	//partition the message
+	partitions, internalMsgId, err := m.partitioner.Partition(recipient, mt, ts,
+		payload)
+	if err != nil {
+		return nil, e2e.MessageID{}, time.Time{}, errors.WithMessage(err, "failed to send unsafe message")
+	}
+
+	jww.INFO.Printf("E2E sending %d messages to %s",
+		len(partitions), recipient)
+
+	//encrypt then send the partitions over cmix
+	roundIds := make([]id.Round, len(partitions))
+	errCh := make(chan error, len(partitions))
+
+	// get the key manager for the partner
+	partner, err := m.Ratchet.GetPartner(recipient)
+	if err != nil {
+		return nil, e2e.MessageID{}, time.Time{}, errors.WithMessagef(err,
+			"Could not send End to End encrypted "+
+				"message, no relationship found with %s", recipient)
+	}
+
+	//return the rounds if everything send successfully
+	msgID := e2e.NewMessageID(partner.GetSendRelationshipFingerprint(), internalMsgId)
+
+	wg := sync.WaitGroup{}
+
+	for i, p := range partitions {
+		if mt != catalog.KeyExchangeTrigger {
+			// check if any rekeys need to happen and trigger them
+			keyExchange2.CheckKeyExchanges(m.Instance, m.SendE2E,
+				m.Events, m.Session, partner,
+				1*time.Minute, stop)
+		}
+
+		//get a key to end to end encrypt
+		var keyGetter func() (*session.Cypher, error)
+		if params.Rekey {
+			keyGetter = partner.PopRekeyCypher
+		} else {
+			keyGetter = partner.PopSendCypher
+		}
+
+		//fixme: remove this wait, it is weird. Why is it here? we cant remember.
+		key, err := waitForKey(keyGetter, params.KeyGetRetryCount,
+			params.KeyGeRetryDelay, params.CMIX.Stop, recipient,
+			format.DigestContents(p), i)
+		if err != nil {
+			return nil, e2e.MessageID{}, time.Time{}, errors.WithMessagef(err,
+				"Failed to get key for end to end encryption")
+		}
+
+		//end to end encrypt the cmix message
+		contentsEnc, mac := key.Encrypt(p)
+
+		jww.INFO.Printf("E2E sending %d/%d to %s with key fp: %s, msgID: %s",
+			i+i, len(partitions), recipient, format.DigestContents(p),
+			key.Fingerprint(), msgID)
+
+		//set up the service tags
+		var s message.Service
+		if i == len(partitions)-1 {
+			s = partner.MakeService(params.LastServiceTag)
+		} else {
+			s = partner.MakeService(params.ServiceTag)
+		}
+
+		//send the cmix message, each partition in its own thread
+		wg.Add(1)
+		go func(i int) {
+			var err error
+			roundIds[i], _, err = m.net.SendCMIX(recipient, key.Fingerprint(),
+				s, contentsEnc, mac, params.CMIX)
+			if err != nil {
+				errCh <- err
+			}
+			wg.Done()
+		}(i)
+	}
+
+	wg.Wait()
+
+	//see if any parts failed to send
+	numFail, errRtn := getSendErrors(errCh)
+	if numFail > 0 {
+		jww.INFO.Printf("Failed to E2E send %d/%d to %s",
+			numFail, len(partitions), recipient)
+		return nil, e2e.MessageID{}, time.Time{}, errors.Errorf("Failed to E2E send %v/%v sub payloads:"+
+			" %s", numFail, len(partitions), errRtn)
+	} else {
+		jww.INFO.Printf("Successfully E2E sent %d/%d to %s",
+			len(partitions)-numFail, len(partitions), recipient)
+	}
+
+	//return the rounds if everything send successfully
+	jww.INFO.Printf("Successful E2E Send of %d messages to %s with msgID %s",
+		len(partitions), recipient, msgID)
+	return roundIds, msgID, ts, nil
+}
+
+// waitForKey waits the designated ammount of time for a
+func waitForKey(keyGetter func() (*session.Cypher, error), numAttempts uint,
+	wait time.Duration, stop *stoppable.Single, recipient *id.ID,
+	digest string, partition int) (*session.Cypher, error) {
+	key, err := keyGetter()
+	if err == nil {
+		return key, nil
+	}
+
+	ticker := time.NewTicker(wait)
+	defer ticker.Stop()
+
+	for keyTries := uint(1); err != nil && keyTries < numAttempts; keyTries++ {
+		jww.WARN.Printf("Out of sending keys for %s "+
+			"(digest: %s, partition: %d), this can "+
+			"happen when sending messages faster than "+
+			"the client can negotiate keys. Please "+
+			"adjust your e2e key parameters",
+			recipient, digest, partition)
+
+		select {
+		case <-ticker.C:
+			key, err = keyGetter()
+		case <-stop.Quit():
+			stop.ToStopped()
+			return nil, errors.Errorf("Stopped by stopper")
+		}
+	}
+
+	return key, err
+}
+
+// getSendErrors returns any errors on the error channel
+func getSendErrors(c chan error) (int, string) {
+	var errRtn string
+	numFail := 0
+	done := false
+	for !done {
+		select {
+		case err := <-c:
+			errRtn += err.Error()
+			numFail++
+		default:
+			done = true
+		}
+	}
+	return numFail, errRtn
+}
diff --git a/go.mod b/go.mod
index 101ca34e6f5c908e2573a5d837cc41d95b3ac97c..0d045618487b259259566189623c0b31ac3990a9 100644
--- a/go.mod
+++ b/go.mod
@@ -15,7 +15,7 @@ require (
 	gitlab.com/elixxir/comms v0.0.4-0.20220308183624-c2183e687a03
 	gitlab.com/elixxir/crypto v0.0.7-0.20220328164108-c72388181116
 	gitlab.com/elixxir/ekv v0.1.6
-	gitlab.com/elixxir/primitives v0.0.3-0.20220325212708-5e2a7a385db7
+	gitlab.com/elixxir/primitives v0.0.3-0.20220330212736-cce83b5f948f
 	gitlab.com/xx_network/comms v0.0.4-0.20220311192415-d95fe8906580
 	gitlab.com/xx_network/crypto v0.0.5-0.20220222212031-750f7e8a01f4
 	gitlab.com/xx_network/primitives v0.0.4-0.20220222211843-901fa4a2d72b
diff --git a/go.sum b/go.sum
index 59dc6cb4ac92695cb2347125b6c174328fc3b3ed..a28b5a590f07d922e1e6993633a57c265559208e 100644
--- a/go.sum
+++ b/go.sum
@@ -297,6 +297,8 @@ gitlab.com/elixxir/primitives v0.0.3-0.20220222212109-d412a6e46623 h1:NzJ06KdJd3
 gitlab.com/elixxir/primitives v0.0.3-0.20220222212109-d412a6e46623/go.mod h1:MtFIyJUQn9P7djzVlBpEYkPNnnWFTjZvw89swoXY+QM=
 gitlab.com/elixxir/primitives v0.0.3-0.20220325212708-5e2a7a385db7 h1:2yIEkxkPJboftkk/xiCONVP/FSl7Y3zOPpekvQ2dhO0=
 gitlab.com/elixxir/primitives v0.0.3-0.20220325212708-5e2a7a385db7/go.mod h1:MtFIyJUQn9P7djzVlBpEYkPNnnWFTjZvw89swoXY+QM=
+gitlab.com/elixxir/primitives v0.0.3-0.20220330212736-cce83b5f948f h1:bOX9nsG+ihvZAUP2OimpM/0UNIcfz5tYlvQfS2IFUoU=
+gitlab.com/elixxir/primitives v0.0.3-0.20220330212736-cce83b5f948f/go.mod h1:9Bb2+u+CDSwsEU5Droo6saDAXuBDvLRjexpBhPAYxhA=
 gitlab.com/xx_network/comms v0.0.0-20200805174823-841427dd5023/go.mod h1:owEcxTRl7gsoM8c3RQ5KAm5GstxrJp5tn+6JfQ4z5Hw=
 gitlab.com/xx_network/comms v0.0.4-0.20220223205228-7c4974139569/go.mod h1:isHnwem0v4rTcwwHP455FhVlFyPcHkHiVz+N3s/uCSI=
 gitlab.com/xx_network/comms v0.0.4-0.20220311192415-d95fe8906580 h1:IV0gDwdTxtCpc9Vkx7IeSStSqvG+0ZpF57X+OhTQDIM=
diff --git a/network/params.go b/network/params.go
index a37eaa3add93d73c58519cf63248b6ba8523c282..a36dcb018f4ae094388ea14b5285c839e9e09802 100644
--- a/network/params.go
+++ b/network/params.go
@@ -137,6 +137,8 @@ func GetDefaultCMIXParams() CMIXParams {
 		RetryDelay:  1 * time.Second,
 		SendTimeout: 3 * time.Second,
 		DebugTag:    "External",
+		//unused single so components that require one have a channel to wait on
+		Stop: stoppable.NewSingle("cmixParamsDefault"),
 	}
 }