+ Start a Discussion
JNicJNic 

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
allAddresses.addAll(email.toAddresses);
if (email.ccAddresses != null) {
allAddresses.addAll(email.ccAddresses);
}

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();
keyPrefixMap.put(tempPrefix,tempName);
}

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) {
            system.debug(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') {
toAddresses.remove(i);
}
}
}
if (ccAddresses != null) {
for (integer i = 0 ; i < ccAddresses.size(); i++) {
string ccAddy = ccAddresses.get(i);
if (ccAddy == 'mytestaddress@mydomain.com') {
ccAddresses.remove(i);
}
}
}
//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
mail.setTargetObjectId(c.contactId);

//Send it back to everyone!
mail.setCcAddresses(ccAddresses);
mail.setToAddresses(toAddresses);

mail.setWhatId(c.id);

//Use the template we got
mail.setTemplateId('00X800000016PCm');

// 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...
mail.setReplyTo('mytestaddress@mydomain.com');

// 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.
mail.setBccSender(false);

// Optionally append the salesforce.com email signature to the email.
// The email address of the user executing the Apex Code will be used.
mail.setUseSignature(false);

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

//Save this as an activity in the case record
mail.setSaveAsActivity(true);
}
}

 

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?

 

Thanks!!

JA-DevJA-Dev

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. 

JNicJNic

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('[<>]', '');
				cleanCcEmails.add(cleanCcEmail);

		    } else {

		    	cleanCcEmails.addAll(email.ccAddresses);
		    }
        }