+ Start a Discussion

Help with email services - parse addresses

Hey guys...


I've recently started digging into email services... I like them, but I'm running into problems with the addresses being added to a string with names and all that...


I'm rebuilding email-to-case as a custom solution because I have no way to "reply to all" instead of just "reply to" when a new case is entered...


Here's where I am at so far:

This class works relatively well...


global class email01 implements Messaging.InboundEmailHandler {

public List<string> allAddresses {get;set;}

global Messaging.InboundEmailResult handleInboundEmail(Messaging.InboundEmail email, Messaging.InboundEnvelope envelope) {

Messaging.InboundEmailResult result = new Messaging.InboundEmailresult();

Contact fromCtc;
Task emTask;
allAddresses = new List<string>();

//Here I am adding all the addresses into one list to make them easier to deal with later
if (email.ccAddresses != null) {

try {
//If this contact is not already in the system...
if ([select count() from contact where email = :email.fromAddress] == 0) {

//specify the new contact
fromCtc = new contact();

//Retrieve the sender's first and last names
String fName = email.fromname.substring(0,email.fromname.indexOf(' '));
String lName = email.fromname.substring(email.fromname.indexOf(' '));

//create the contact
fromCtc.firstName = fName;
fromCtc.LastName = lName;
fromCtc.Email = email.fromAddress;
insert fromCtc;

//otherwise - select the one in the system
} else {
fromCtc = [select id from contact where email = :email.fromAddress];

//specify the ref tags we use
string startRef = '[ tioref:';
string endRef = ':tioref ]';

//Now we need to figure out what this is in regards to:
// Note that business rules determine this by the toAddress
// of the message, or the refId
//Now if the subject contains both of those ref numbers, then we should act on it
if(email.subject.contains(startRef) && email.subject.contains(endRef)) {

//Lets pull the id out of the subject string
string refId = email.subject.substring(email.subject.indexOf(startRef) + 9, email.subject.indexOf(endRef));

//Now that we've gotten that... Let's query the db for it and find out what it is:

Map<String, Schema.SObjectType> gd = Schema.getGlobalDescribe();
Map<String,String> keyPrefixMap = new Map<String,String>{};
Set<String> keyPrefixSet = gd.keySet();
for(String sObj : keyPrefixSet){
Schema.DescribeSObjectResult r = gd.get(sObj).getDescribe();
String tempName = r.getName();
String tempPrefix = r.getKeyPrefix();

string tPrefix = refId.subString(0,3);
string objectName = keyPrefixMap.get(tPrefix);
System.debug('objectName:::::' + objectName);

//If this is a case
if (objectName == 'Case') {
//go do this...
caseEmailHelper.caseEmail(refId, email.fromAddress, email.fromName, email.toAddresses, email.ccAddresses, email.subject, email.plainTextBody);
//Otherwise I wanna determine what address it was sent to - right now I just have one test address... I don't think this is a right way to do it, but I'm not sure.
else {
                for (string address : allAddresses) {
                    if (address == 'mytestaddress@mydomain.com') {
                        caseEmailHelper.caseEmail(null, email.fromAddress, email.fromName, email.toAddresses, email.ccAddresses, email.subject, email.plainTextBody);
            result.success = true;
        //Otherwise - debug it, and blame it on someone else...
        catch (exception e) {
            result.success = false;
        return result;





This class is having some problems...


public with sharing class caseEmailHelper {

public Case c {get;set;}
public EmailMessage e {get;set;}

public static void caseEmail(String id, String fromAddress, String fromName, List<string> toAddresses, List<string> ccAddresses, String subject, String body) {

Case c = new Case();
Contact ctc = [select id from contact where email = :fromAddress];

//If this is a new case - meaning we do not have an ID
if ([select count() from Case where id = :id] == 0) {
//Then create the case and set the mandatory fields...
c = new Case();
c.Subject = subject;
c.Description = body;
c.Origin = 'Email';
c.ContactId = ctc.Id;
insert c;
//... and send a reply
caseReply(c.id, fromAddress, fromName, toAddresses, ccAddresses, subject, body);

} else {
c = [select id from Case where id = :id];

EmailMessage e = new EmailMessage();
//Iterate through the toAddresses and add them to the email toAddress
for ( integer i = 0 ; i < toAddresses.size(); i++) {
if (e.ToAddress == null) {
e.ToAddress = toAddresses[i];
} else {
e.toAddress = e.toAddress + '; ' + toAddresses[i];
e.FromAddress = fromAddress;
e.fromName = fromName;
//iterate through the ccAddresses and add them to the ccAddress
//NOTE this could be null... so lets make sure to check that...
if (ccAddresses != null ) {
for ( integer i = 0 ; i < ccAddresses.size(); i++) {
if (e.CcAddress == null) {
e.CcAddress = ccAddresses[i];
} else {
e.CcAddress = e.CcAddress + '; ' + ccAddresses[i];
e.subject = subject;
e.ParentId = c.id;
e.Incoming = true;
e.TextBody = body;
e.MessageDate = system.Datetime.now();
//Status 0 = New, 1 = Read, 2 = Replied, 3 = Sent, 4 = Forwarded
e.status = '0';
insert e;

//Sending a reply
// Note that I have passed an ID even though I may already have one
// this means i might just be able to call this from other places later...
public static void caseReply(String id, String fromAddress, String fromName, List<string> toAddresses, List<string> ccAddresses, String subject, String body) {

Case c = [select id, contactId from Case where id = :id];

if (toAddresses != null) {
for (integer i = 0 ; i < toAddresses.size(); i++) {
string toAddy = toAddresses.get(i);
if (toAddy == 'mytestaddress@mydomain.com') {
if (ccAddresses != null) {
for (integer i = 0 ; i < ccAddresses.size(); i++) {
string ccAddy = ccAddresses.get(i);
if (ccAddy == 'mytestaddress@mydomain.com') {
//Do something else for now...

// Create a new single email message object
// that will send out a single email to the addresses in the To, CC & BCC list.
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();

//send this to the id we have specified

//Send it back to everyone!


//Use the template we got

// Specify the address used when the recipients reply to the email.
// NOTE this does not seem to work when using templates... even if I removed the setReplyTo in the template...
// you MUST use a set replyToIn this template to keep working...

// Specify the name used as the display name.
mail.setSenderDisplayName('TIO Networks Support');

// Set to True if you want to BCC yourself on the email.

// Optionally append the salesforce.com email signature to the email.
// The email address of the user executing the Apex Code will be used.

// Send the email you have created.
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });

//Save this as an activity in the case record


my problem seems to be on the blue line... it doesn't like my addresses....

Debug log:

System.EmailException: SendEmail failed. First exception on row 0; first error: INVALID_EMAIL_ADDRESS, Invalid to address : John Doe <john.doe@gmail.com>: []


I guess it has something to do with just passing those address strings with all the other characters in them... how I can get rid of those in email01 class and just pass something nice and clean?




You will have to clean the email string up prior to adding it to the list. Right before you add an email string to the list, do a split on a single space (emailString.split(" ",0)) which will provide you with an array of tokens. From those tokens, you only want the token that contains the "@" character and then, you'd remove the "<" and ">" characters from those tokens. 


I found someone else did this - and I implemented it... it seems to work...


Is this a good practice?




        //Clean the "ccAddresses" list
        for (string ccAddress : email.ccAddresses) {
        	Matcher matcher = pattern.compile('<.+>').matcher(ccAddress);

			//Parse it to emails and add it to our clean list
		    if (matcher.find()) {

				string cleanCcEmail = matcher.group().replaceAll('[<>]', '');

		    } else {