Monday, January 23, 2012

Email-To-Case custom email handler - Common Subjects

My users are quite happy with the drastic reduction in duplicate cases because my email to case handler is matching on subject lines and simply appending emails to existing cases. As mentioned above this test compares the incoming email subject line to Cases created in the last five days. Before comparison the subject line is stripped of the typical prefixes such as FW: and RE:

But, today they pointed out that emails from our web site are all getting dumped into the same case. We have a link like this on our web site:
email

The result is we get numerous emails with this same subject line; and my email to case handler puts them all into the same case. Not what we want!

What to do? Answer: have a list of commonly expected subject lines.

Where to put this list? In the code? No! Answer: Salesforce Custom Settings

I don't know about others but I found the documentation hard to understand:
http://www.salesforce.com/us/developer/docs/apexcode/index.htm
https://help.salesforce.com/apex/htviewhelpdoc?id=cs_add_data.htm&language=en

I found this blog more useful:
http://cloudnow.wordpress.com/2011/04/20/custom-settings-how-and-why/

But I'm still not sure about how best to use Custom Settings. Yet, I did get them to work for this common subject line problem.

As per documentation;

  1. create a new Custom Setting object called EmailToCase__c
  2. create a field in this object called CommonSubjects__c
  3. click Manage on the object 
  4. click New (this was the weird part. What do you do?) The edit screen has two inputs "Name" and "CommonSubjects".  Eventually I realized this is Name and Value.  I entered: Name =  WebContactUsForm   Value = CommonSubjects:    Inquiry from link on Carmanah Technologies web site 
  5. Repeat step 4 for any other common subjects.
The EmailToCase__c object now has a text field. To skip common subject lines we iterate over all EmailToCase__c objects and test the incoming subject line to one of the settings.

In the CaseEmailInBoundUtilities class' processInboundEmail method insert the following code just before searching for matching subject lines:
 // try to match subject
 String mainSubject = extractMainSubject(email.subject);
 if(mainSubject!=null) {
 Boolean proceedToTestForMatch = true;
 
 Map eToCaseSettings = EmailToCase__c.getAll();
 List subjectLines = new List();
 subjectLines.addAll(eToCaseSettings.keySet());
 for (String key : subjectLines) {
  EmailToCase__c eToC = eToCaseSettings.get(key);
  if(eToC.CommonSubjects__c.equals(mainSubject)) {
   System.debug('Matched common subject line. Name: ' +eToC.Name + ' Subject: '+ eToC.CommonSubjects__c );
   proceedToTestForMatch = false;
  }
 }  
 if(proceedToTestForMatch 
.... continue to rest of method that searches for Cases with matching subject line.




For the record here is the complete method
public Messaging.InboundEmailResult processInboundEmail(Messaging.InboundEmail email)
{
 Messaging.InboundEmailResult result = new Messaging.InboundEmailresult();
 result.success = true;
 this.inboundEmail = email;
 

 String caseNumber = extractRef(email.subject);
 if(caseNumber != null)
 {  
  if(TRACE)system.debug(Logginglevel.ERROR,'CaseEmailInBoundUtilities.  extracted case number: "' + caseNumber + '"');
  this.theCase = locateByCaseNumberAsString(caseNumber);
  if(this.theCase == null) {
   // TODO email error message to SysAdmin
   system.debug(Logginglevel.ERROR,'CaseEmailInBoundUtilities.  Create a new case.  Could not find case number: "' + caseNumber + '"');
  }
 } else {
  // try to match subject
  String mainSubject = extractMainSubject(email.subject);
  if(mainSubject!=null) {
  Boolean proceedToTestForMatch = true;
  
  Map eToCaseSettings = EmailToCase__c.getAll();
        List subjectLines = new List();
        subjectLines.addAll(eToCaseSettings.keySet());
        for (String key : subjectLines) {
            EmailToCase__c eToC = eToCaseSettings.get(key);
            if(eToC.CommonSubjects__c.equals(mainSubject)) {
             System.debug('Matched common subject line. Name: ' +eToC.Name + ' Subject: '+ eToC.CommonSubjects__c );
             proceedToTestForMatch = false;
            }
        }  
  // Only try to match non-trivial subject lines. Otherwise too many different issues can me merged into one case.
  if(proceedToTestForMatch && mainSubject.length() > 15) {
   // Only match subjects on cases Created in the last 5 days. 
   Case[] matchingCases = [Select Id, CaseNumber, Subject, Description 
       from Case where Subject = :mainSubject
    and CreatedDate = LAST_N_DAYS:5];
   if(matchingCases.size() == 1) {
    this.theCase = matchingCases[0];
   } else 
   {
    system.debug(Logginglevel.ERROR,'CaseEmailInBoundUtilities.  Create a new case because we found '+matchingCases.size() + ' cases with the subject: "' + mainSubject + '"');
   }
  }
  }
 }
 if(this.theCase == null) {
  // else create a new Case
  this.theCase = new Case();
  theCase.SuppliedEmail = email.fromAddress;
  theCase.SuppliedName = email.fromName;
  theCase.Status = 'New';
  theCase.Priority = 'Low';
  theCase.OwnerId = this.defaultCaseOwnerId;
        theCase.Origin = 'Email';
        String extractedSubject = extractMainSubject(email.subject);        
  theCase.Subject = extractedSubject;
  theCase.Description = email.plainTextBody;
  
  Contact[] contacts = [SELECT Id, Name, AccountId, Email FROM Contact WHERE Email = :email.fromAddress];
  if(contacts.size() >0) 
  {
   Contact theContact = contacts[0];
   theCase.ContactId = theContact.Id;
   theCase.AccountId = theContact.AccountId;   
   if(contacts.size() > 1) {
    // Could-Should create a new Case here to get CS to resolve this....
    theCase.Description = 'Note: there is more than on Contact with this email address. Fix this. ' + theCase.Description;
   }
  }
  insertSObject(this.theCase);
 }

 createEmailMessage(theCase,email);
 handleAttachments(theCase, email);
 return result;
}


2 comments:

  1. Hey Bryan, I think your post on the inbound email handler code is pretty awesome. I've made some adjustments to things, but was running into a similar issue where the inbound emails were being added to the same case. Basically, everyone sending an inbound email is using a template in Outlook, so the email subjects are identical. I was trying to amend my inbound email handler with the above code and was running into unexpected token issues. I'm not a coder by any means and much more of a button-click admin, but I am trying to learn some code. Anyways, I think either your code is outdated for the new API or there are errors in it. I was updating it and ran into the unexpected token "subjectLines.addAll" I had alread updated the first part of the code as below.

    Map eToCaseSettings = EmailToCase__c.getAll();
    List subjectLines = new List
    subjectLines.addAll(eToCaseSettings.keySet());
    for (String key : subjectLines) {
    EmailToCase__c eToC = eToCaseSettings.get(key);
    if(eToC.CommonSubjects__c.equals(mainSubject)) {
    System.debug('Matched common subject line. Name: ' +eToC.Name + ' Subject: '+ eToC.CommonSubjects__c );
    proceedToTestForMatch = false;
    }
    }

    Can you let me know why is wrong with the code in regards to the Keyset line? I'm assuming that the code below might need to be updated as well, I was just adjusting things from the top down until it reached an error. Correct me if I'm wrong, but I had changed the first two lines after reading some documentation and it seems that this is how the lines should be.

    ReplyDelete
    Replies
    1. Thanks for the feedback. I think the line "List subjectLines = new List" needs to be "List subjectLines = new List()". Note the ().


      Delete