diff --git a/api/client.go b/api/client.go
index 4d0382c44eb6e4c75c955bbb0b3438ee4263fca6..22f94b9c953e009613b3520242557396931a6ef4 100644
--- a/api/client.go
+++ b/api/client.go
@@ -124,8 +124,9 @@ func NewPrecannedClient(precannedID uint, defJSON, storageDir string, password [
 	// Save NDF to be used in the future
 	storageSess.SetBaseNDF(def)
 
-	//move the registration state to keys generated
-	err = storageSess.ForwardRegistrationStatus(storage.KeyGenComplete)
+	//move the registration state to indicate registered with permissioning
+	err = storageSess.ForwardRegistrationStatus(
+		storage.PermissioningComplete)
 	if err != nil {
 		return errors.WithMessage(err, "Failed to denote state "+
 			"change in session")
diff --git a/api/user.go b/api/user.go
index 0fafdbb5a35eb7f2d6ec2578218e66781e56c54f..1f90d7c92adb7e75649b838381d4be80ab1a9c45 100644
--- a/api/user.go
+++ b/api/user.go
@@ -85,10 +85,19 @@ func createPrecannedUser(precannedID uint, rng csprng.Source, cmix, e2e *cyclic.
 	binary.BigEndian.PutUint64(userID[:], uint64(precannedID))
 	userID.SetType(id.User)
 
+	// NOTE: not used... RSA Keygen (4096 bit defaults)
+	rsaKey, err := rsa.GenerateKey(rng, rsa.DefaultRSABitLen)
+	if err != nil {
+		jww.FATAL.Panicf(err.Error())
+	}
+
 	return user.User{
 		ID:              userID.DeepCopy(),
 		Salt:            salt,
-		Precanned:       false,
+		Precanned:       true,
 		E2eDhPrivateKey: e2e.NewIntFromBytes(e2eKeyBytes),
+		// NOTE: These are dummy/not used
+		CmixDhPrivateKey: cmix.NewInt(1),
+		RSA:              rsaKey,
 	}
 }
diff --git a/cmd/root.go b/cmd/root.go
index 227d38d598fa1c068e2829da29aa17bbfafaad6b..c45ffd0b4f39268835c8d6ac1f0d18b4efe7a4e7 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -8,6 +8,7 @@
 package cmd
 
 import (
+	"encoding/base64"
 	"encoding/binary"
 	"encoding/hex"
 	"fmt"
@@ -22,6 +23,7 @@ import (
 	"io/ioutil"
 	"os"
 	"strconv"
+	"strings"
 	"time"
 )
 
@@ -103,8 +105,7 @@ var rootCmd = &cobra.Command{
 		pass := viper.GetString("password")
 		storeDir := viper.GetString("session")
 		regCode := viper.GetString("regcode")
-		precannedID := viper.GetUint("precannedID")
-		precannedPartner := viper.GetUint("precannedPartner")
+		precannedID := viper.GetUint("sendid")
 
 		//create a new client if none exist
 		if _, err := os.Stat(storeDir); os.IsNotExist(err) {
@@ -116,8 +117,8 @@ var rootCmd = &cobra.Command{
 			}
 
 			if precannedID != 0 {
-				err = api.NewPrecannedClient(precannedID, string(ndfJSON),
-					storeDir, []byte(pass))
+				err = api.NewPrecannedClient(precannedID,
+					string(ndfJSON), storeDir, []byte(pass))
 			} else {
 				err = api.NewClient(string(ndfJSON), storeDir,
 					[]byte(pass), regCode)
@@ -134,10 +135,6 @@ var rootCmd = &cobra.Command{
 			jww.FATAL.Panicf("%+v", err)
 		}
 
-		if precannedPartner != 0 {
-			client.MakePrecannedContact(precannedPartner)
-		}
-
 		user := client.GetUser()
 		jww.INFO.Printf("%s", user.ID)
 
@@ -160,21 +157,42 @@ var rootCmd = &cobra.Command{
 
 		// Send Messages
 		msgBody := viper.GetString("message")
-		//recipientID := getUIDFromString(viper.GetString("destid"))
-		recipientID := user.ID
+		recipientID, isPrecanPartner := parseRecipient(
+			viper.GetString("destid"))
+
+		if isPrecanPartner {
+			jww.WARN.Printf("Precanned user id detected: %s",
+				recipientID)
+			preUsr, err := client.MakePrecannedAuthenticatedChannel(
+				getPrecanID(recipientID))
+			if err != nil {
+				jww.FATAL.Panicf("%+v", err)
+			}
+			// Sanity check, make sure user id's haven't changed
+			preBytes := preUsr.ID.Bytes()
+			idBytes := recipientID.Bytes()
+			for i := 0; i < len(preBytes); i++ {
+				if idBytes[i] != preBytes[i] {
+					jww.FATAL.Panicf("no id match: %v %v",
+						preBytes, idBytes)
+				}
+			}
+		} else {
+			jww.FATAL.Panicf("e2e unimplemented")
+		}
 
 		msg := message.Send{
 			Recipient:   recipientID,
 			Payload:     []byte(msgBody),
 			MessageType: message.Text,
 		}
-		params := params.GetDefaultUnsafe()
+		params := params.GetDefaultE2E()
 
 		sendCnt := int(viper.GetUint("sendCount"))
 		sendDelay := time.Duration(viper.GetUint("sendDelay"))
 		for i := 0; i < sendCnt; i++ {
 			fmt.Printf("Sending to %s: %s\n", recipientID, msgBody)
-			roundIDs, err := client.SendUnsafe(msg, params)
+			roundIDs, _, err := client.SendE2E(msg, params)
 			if err != nil {
 				jww.FATAL.Panicf("%+v", err)
 			}
@@ -239,7 +257,34 @@ func waitUntilConnected(connected chan bool) {
 	}()
 }
 
-func getUIDFromString(idStr string) *id.ID {
+func getPrecanID(recipientID *id.ID) uint {
+	return uint(recipientID.Bytes()[7])
+}
+
+func parseRecipient(idStr string) (*id.ID, bool) {
+	var recipientID *id.ID
+	if strings.HasPrefix(idStr, "0x") {
+		recipientID = getUIDFromHexString(idStr[2:])
+	} else if strings.HasPrefix(idStr, "b64:") {
+		recipientID = getUIDFromb64String(idStr[4:])
+	} else {
+		recipientID = getUIDFromString(idStr)
+	}
+	// check if precanned
+	rBytes := recipientID.Bytes()
+	for i := 0; i < 32; i++ {
+		if i != 7 && rBytes[i] != 0 {
+			return recipientID, false
+		}
+	}
+	if rBytes[7] != byte(0) && rBytes[7] <= byte(40) {
+		return recipientID, true
+	}
+	jww.FATAL.Panicf("error recipient id parse failure: %+v", recipientID)
+	return recipientID, false
+}
+
+func getUIDFromHexString(idStr string) *id.ID {
 	idBytes, err := hex.DecodeString(fmt.Sprintf("%0*d%s",
 		66-len(idStr), 0, idStr))
 	if err != nil {
@@ -252,6 +297,37 @@ func getUIDFromString(idStr string) *id.ID {
 	return ID
 }
 
+func getUIDFromb64String(idStr string) *id.ID {
+	idBytes, err := base64.StdEncoding.DecodeString(idStr)
+	if err != nil {
+		jww.FATAL.Panicf("%+v", err)
+	}
+	ID, err := id.Unmarshal(idBytes)
+	if err != nil {
+		jww.FATAL.Panicf("%+v", err)
+	}
+	return ID
+}
+
+func getUIDFromString(idStr string) *id.ID {
+	idInt, err := strconv.Atoi(idStr)
+	if err != nil {
+		jww.FATAL.Panicf("%+v", err)
+	}
+	if idInt > 255 {
+		jww.FATAL.Panicf("cannot convert integers above 255. Use 0x " +
+			"or b64: representation")
+	}
+	idBytes := make([]byte, 33)
+	binary.BigEndian.PutUint64(idBytes, uint64(idInt))
+	idBytes[32] = byte(id.User)
+	ID, err := id.Unmarshal(idBytes)
+	if err != nil {
+		jww.FATAL.Panicf("%+v", err)
+	}
+	return ID
+}
+
 func initLog(verbose bool, logPath string) {
 	if logPath != "-" && logPath != "" {
 		// Disable stdout output
@@ -332,8 +408,13 @@ func init() {
 	rootCmd.Flags().StringP("message", "m", "", "Message to send")
 	viper.BindPFlag("message", rootCmd.Flags().Lookup("message"))
 
+	rootCmd.Flags().UintP("sendid", "", 0,
+		"Use precanned user id (must be between 1 and 40, inclusive)")
+	viper.BindPFlag("sendid", rootCmd.Flags().Lookup("sendid"))
+
 	rootCmd.Flags().StringP("destid", "d", "0",
-		"ID to send message to (hexadecimal string up to 256 bits)")
+		"ID to send message to (if below 40, will be precanned. Use "+
+			"'0x' or 'b64:' for hex and base64 representations)")
 	viper.BindPFlag("destid", rootCmd.Flags().Lookup("destid"))
 
 	rootCmd.Flags().UintP("sendCount",
diff --git a/go.mod b/go.mod
index cb12a1912af2fd850c13bc7c4c96a200eb9b459f..e687ec1957c6d2be89589ede34d35ab960bfd9bd 100644
--- a/go.mod
+++ b/go.mod
@@ -13,7 +13,7 @@ require (
 	github.com/spf13/cobra v1.0.0
 	github.com/spf13/jwalterweatherman v1.1.0
 	github.com/spf13/viper v1.7.1
-	gitlab.com/elixxir/comms v0.0.0-20201006010513-3353fb46569a
+	gitlab.com/elixxir/comms v0.0.0-20201008193723-5ec1168cdead
 	gitlab.com/elixxir/crypto v0.0.0-20201006010428-67a8782d097e
 	gitlab.com/elixxir/ekv v0.1.3
 	gitlab.com/elixxir/primitives v0.0.0-20201007182231-b9aef2de8219
diff --git a/go.sum b/go.sum
index 8cc0d6f662861956a3745ff8fcc0ceabf0fecfa3..9fb2ed197ab0a70d94d47dc758dbed66b51cf332 100644
--- a/go.sum
+++ b/go.sum
@@ -293,6 +293,8 @@ gitlab.com/elixxir/comms v0.0.0-20201005232129-4fcbcb1b8720 h1:xfwI2qQLsfnDr0Q/J
 gitlab.com/elixxir/comms v0.0.0-20201005232129-4fcbcb1b8720/go.mod h1:dPnkkC3b+lPIh/nzpGN8VoDieKUj+lmWTGDRsA7Rwns=
 gitlab.com/elixxir/comms v0.0.0-20201006010513-3353fb46569a h1:pEqtyTf9h1tPem2O4BXTDCVF8KOJMQKxUkvQz2qgl9Y=
 gitlab.com/elixxir/comms v0.0.0-20201006010513-3353fb46569a/go.mod h1:ISDCOoSsgkzKJj69UUXQf0TVeJOmrdOYv9MofxEJWcg=
+gitlab.com/elixxir/comms v0.0.0-20201008193723-5ec1168cdead h1:dKUiSKGZOTaIOXiCybvy4mfGh1TGB1IWnS1tYw0SfSo=
+gitlab.com/elixxir/comms v0.0.0-20201008193723-5ec1168cdead/go.mod h1:ISDCOoSsgkzKJj69UUXQf0TVeJOmrdOYv9MofxEJWcg=
 gitlab.com/elixxir/crypto v0.0.0-20200707005343-97f868cbd930/go.mod h1:LHBAaEf48a0/AjU118rjoworH0LgXifhAqmNX3ZRvME=
 gitlab.com/elixxir/crypto v0.0.0-20200731174640-0503cf80524a/go.mod h1:LHBAaEf48a0/AjU118rjoworH0LgXifhAqmNX3ZRvME=
 gitlab.com/elixxir/crypto v0.0.0-20200804182833-984246dea2c4 h1:28ftZDeYEko7xptCZzeFWS1Iam95dj46TWFVVlKmw6A=