Inbound Email Service

Inbound Email Service

Use Apex to work with email sent to Salesforce.

You can use Apex to receive and process email and attachments. The email is received by the Apex email service, and processed by Apex classes that utilize the InboundEmail object.

You can use email services to process the contents, headers, and attachments of inbound email. For example, you can create an email service that automatically creates contact records based on contact information in messages.

You can associate each email service with one or more Salesforce-generated email addresses to which users can send messages for processing

Email services are special-purpose Force.com processes that use Apex classes to process incoming email messages.

1. Generate a special email address on which Force.com will receive your emails
2. The email services will then invoke a method on the Apex class whenever an email is received on the email address.

Since they result in Apex logic being executed, the emails can be made to invoke any number of actions.

Force.com allows you to enforce additional security:

You can limit the email senders to specific addresses or domains – Force.com will reject emails from other addresses/domains.

You can enable advanced security if the sender domain(s) support one or more of the protocols SPF, Sender ID, and DomainKeys. This ensures that spoofed emails do not get through.

Scenario:
Customers  email to sfdcmeet@support.com needs to be processed automatically by extracting the email content – address, subject, body, attachment and create a case record into salesforce.

Case Subject – email subject
Case Description – email body

Step 1: Build an inbound email handler Apex class for processing the email

An Apex class that acts as an inbound email handler simply needs to implement the Messaging.InboundEmailHandler interface. The interface defines a single method – handleInboundEmail(Messaging.InboundEmail email, Messaging.Inboundenvelope envelope)):

global class EmailDemoReceive implements Messaging.InboundEmailHandler {
  global Messaging.InboundEmailResult handleInboundEmail(Messaging.InboundEmail email, 
                                                         Messaging.Inboundenvelope envelope) {

 

The message contents are available through the email argument, and the envelope stores the to and from address.

Messaging.InboundEmal email     -> subject, content of the email.
Messaging.inboundEnvelope env -> to receive the to and from addresses of the email.

As a good practice:

  1. Create a result to show whether your processing succeeded or failed. A value of null is taken as success, but it is better to make this explicit.
  2. Note that we process everything in a try-catch block. This is not sufficient handling of exceptions and the same in detailed will be updated later in this page.

The complete apex class would like this.

public class InboundEmailDemo implements Messaging.InboundEmailHandler{
    public Messaging.InboundEmailResult handleInboundEmail(Messaging.inboundEmail email, 
                                                           Messaging.InboundEnvelope envelope){
        Messaging.InboundEmailResult result = new Messaging.InboundEmailResult();
        try{
            Case c = new Case();
            c.Subject = email.subject;
            c.Description = email.plainTextBody;
            c.Origin = 'Email';
            c.Priority = 'High';
            c.Status = 'New';
            insert c; 
            result.success = true;
        } catch(Exception e){
            String errorMessage = e.getMessage();
            result.message = errorMessage;
            result.success = false;            
        }
        return result;                                                               
    }
}

Step 2: Create Email Service

Next, you need to define the email service. This establishes an email address, which you can then tie to the Apex class that you’ve just written. Define the email service by logging into your environment:

  1. Log into Force.com and select on Setup->App Setup->Develop->Email Services
  2. Select New Email Service

Filling this in is straightforward:

  1. Give a name for Email Service Name, like say “EmailDemoReceive”
  2. For Apex Class, specify the Apex class you just built
  3. You can leave the rest of the fields at their default values for starters
  4. Hit Save

That’s it, you’ve created your first email service. But you still need to generate an email address on which Force.com will listen for incoming emails. To do that, select New Email Address and fill as follows:

  1. Choose an id for Email address. This can be anything, like say “invoices” if you plan to process invoices with this address.
  2. Check Active.
  3. Set Context User – this specifies the context under which the Apex class will run. It defaults to you, but you’re free to pick another user from your organization.
  4. For Accept Emails From, give a comma-separated list of addresses (a@b.com) or domains (b.com) that Email Services can accept emails from. If you leave it blank, all addresses will work.
  5. Hit Save.

As a result you might an email something like this – sfdcmeetsupport@7-2zgly5zbh5ge7ktx88pui5sa5jl2brm0ghwpk5ok9saym5uiln.28-1eudreaa.ap2.apex.salesforce.com

That’s it! Any email sent to the above email address will now result in the Apex class being executed. You would typically alias this email address behind one in your own domain.

In summary, to handle inbound emails all you have to do is: · Create an Apex class that implements Messaging.InboundEmailHandler · Create an email service that binds to that Apex class · Create one or more email addresses, associated with the email service

Scenario 2:

global class InboundEmailExample2 implements Messaging.InboundEmailHandler {
 
  global Messaging.InboundEmailResult handleInboundEmail(Messaging.inboundEmail email, 
                                                       Messaging.InboundEnvelope env){
 
    // Create an InboundEmailResult object for returning the result of the 
    // Apex Email Service
    Messaging.InboundEmailResult result = new Messaging.InboundEmailResult();
  
    String myPlainText= '';
    
    // Add the email plain text into the local variable 
    myPlainText = email.plainTextBody;
   
    // New Task object to be created
    Task[] newTask = new Task[0];
   
    // Try to look up any contacts based on the email from address
    // If there is more than one contact with the same email address,
    // an exception will be thrown and the catch statement will be called.
    try {
      Contact vCon = [SELECT Id, Name, Email
        FROM Contact
        WHERE Email = :email.fromAddress
        LIMIT 1];
      
      // Add a new Task to the contact record we just found above.
      newTask.add(new Task(Description =  myPlainText,
           Priority = 'Normal',
           Status = 'Inbound Email',
           Subject = email.subject,
           IsReminderSet = true,
           ReminderDateTime = System.now()+1,
           WhoId =  vCon.Id));
     
     // Insert the new Task 
     insert newTask;    
     
     System.debug('New Task Object: ' + newTask );   
    }
    // If an exception occurs when the query accesses 
    // the contact record, a QueryException is called.
    // The exception is written to the Apex debug log.
      catch (QueryException e) {
       System.debug('Query Issue: ' + e);
   }
   
   // Set the result to true. No need to send an email back to the user 
   // with an error message
   result.success = true;
   
   // Return the result for the Apex Email Service
   return result;
  }
}

Test Class

@isTest
private class InboundEmailExample2Test {
    @isTest
    static void myTest(){
      contact c = new contact(lastName = 'Aparna', email = 'vkranjithkrishnan@gmail.com');
      insert c;
      InboundEmailExample2 inb1 = new InboundEmailExample2();
      Messaging.inboundEmail email = new Messaging.inboundEmail();
      email.fromAddress = c.email;
      email.subject = 'Test Subject';
      email.plainTextBody = 'my plain text';
        
      Messaging.InboundEnvelope env = new Messaging.InboundEnvelope();        
      inb1.handleInboundEmail(email, env);        
    }

}

Scenario 3: With Attachments

global class ProcessJobApplicantEmail implements Messaging.InboundEmailHandler {

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

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

    Contact contact = new Contact();
    contact.FirstName = email.fromname.substring(0,email.fromname.indexOf(' '));
    contact.LastName = email.fromname.substring(email.fromname.indexOf(' '));
    contact.Email = envelope.fromAddress;
    insert contact;

    System.debug('====> Created contact '+contact.Id);

    if (email.binaryAttachments != null && email.binaryAttachments.size() > 0) {
      for (integer i = 0 ; i < email.binaryAttachments.size() ; i++) {
        Attachment attachment = new Attachment();
        // attach to the newly created contact record
        attachment.ParentId = contact.Id;
        attachment.Name = email.binaryAttachments[i].filename;
        attachment.Body = email.binaryAttachments[i].body;
        insert attachment;
      }
    }

    return result;

  }

}

Test Class

static testMethod void testMe() {

  // create a new email and envelope object
  Messaging.InboundEmail email = new Messaging.InboundEmail() ;
  Messaging.InboundEnvelope env = new Messaging.InboundEnvelope();

  // setup the data for the email
  email.subject = 'Test Job Applicant';
  email.fromname = 'FirstName LastName';
  env.fromAddress = 'someaddress@email.com';

  // add an attachment
  Messaging.InboundEmail.BinaryAttachment attachment = new Messaging.InboundEmail.BinaryAttachment();
  attachment.body = blob.valueOf('my attachment text');
  attachment.fileName = 'textfile.txt';
  attachment.mimeTypeSubType = 'text/plain';

  email.binaryAttachments =
    new Messaging.inboundEmail.BinaryAttachment[] { attachment };

  // call the email service class and test it with the data in the testMethod
  ProcessJobApplicantEmail emailProcess = new ProcessJobApplicantEmail();
  emailProcess.handleInboundEmail(email, env);

  // query for the contact the email service created
  Contact contact = [select id, firstName, lastName, email from contact
    where firstName = 'FirstName' and lastName = 'LastName'];

  System.assertEquals(contact.firstName,'FirstName');
  System.assertEquals(contact.lastName,'LastName');
  System.assertEquals(contact.email,'someaddress@email.com');

  // find the attachment
  Attachment a = [select name from attachment where parentId = :contact.id];

  System.assertEquals(a.name,'textfile.txt');

}