An Introduction to Email Services

Abstract

Force.com provides powerful, robust, and secure functionality for sending and receiving email. You can configure the platform to execute complex Apex Code logic when an email is received, and you can use the email services to send out emails from within the platform. Force.com handles most of the messaging chores for you, letting you focus on your business logic.

This article describes how to configure the email functionality on Force.com and how to build Apex classes to send and receive emails.

Introduction

Email is a fundamental part of everyone’s business life, so it makes sense to include it as a part of your business applications as well. Force.com provides robust services for reacting to incoming email and for sending email as part of your business application.

This article examines both aspects of email. Receiving Email looks at how to set up an email address on Force.com and create an Apex class to process incoming emails. Sending Email looks at how you can send emails from the platform.

Receiving Email

Email services are special-purpose Force.com processes that use Apex classes to process incoming email messages. When you set up an email service, you generate a special email address on which Force.com will receive your emails. You also supply an Apex class adhering to a particular interface. The email services will then invoke a method on the Apex class whenever an email is received on the email address.

Because email services accept standard email, they open up the possibility to use any email client to interact with your applications using simple text, rather than with structured web services. Since they result in Apex logic being executed, the emails can be made to invoke any number of actions. For example, you can use anything from an iPhone to a web client to a legacy application to create invoices, launch workflows, or generate email threads.

As inbound emails can cause material business changes, 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.

The rest of this section shows how to set up your inbound email service and write a simple Apex class to react to incoming email. Setting up an email service is simple:

  1. Build an inbound email handler Apex class for processing the email
  2. Configure the email service, binding it to the Apex class

Let’s dig in!

The Inbound Email Handler

An Apex class that acts as an inbound email handler simply needs to implement the Messaging.InboundEmailHandler interface. The interface defines a single method:

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.

Here is an example that shows how you can use these objects to access different fields in the incoming email. This class processes incoming email as follows:

  1. Create a new Account record with the email subject as the account name
  2. Generate contacts based on the names on the cc-list
  3. Save the text and binary attachments
  4. Store the email body as a note

Here’s a walk through of the entire class, a few lines at a time: First, the class implements the Messaging.InboundEmailHandler interface, and all the activity happens in the handleInboundEmail() method.

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

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 though, as explained in the Appendix
   
    …
    Account account;
    Messaging.InboundEmailResult result = new Messaging.InboundEmailResult();
   
    try {
    …
 

The email and envelope arguments have several public attributes you can access directly. First, let’s grab the email’s subject and create a new account record if it doesn’t already exist.

   
      …
      // Look for account whose name is the subject and create it if necessary
      if ([select count() from Account where Name = :email.subject] == 0) {
        account = new Account();
        account.Name = email.subject;
        insert account;
      } else {
        account = [select Id from Account where Name = :email.subject];
      }

Now we’ll process the email addresses in the CC:

 
      // Convert cc'd addresses to contacts
      for (String address : email.ccAddresses) {
        Contact contact = new Contact();
        Matcher matcher = Pattern.compile('<.+>').matcher(address);
       
        // Parse addresses to names and emails
        if (matcher.find()) {
          String[] nameParts = address.split('[ ]*<.+>')[0].replace('"', '').split('[ ]+');
         
          contact.FirstName = nameParts.size() > 1 ? nameParts[0] : '';
          contact.LastName = nameParts.size() > 1 ? nameParts[nameParts.size()-1] : nameParts[0];
          contact.Email = matcher.group().replaceAll('[<>]', '');
        } else {
          contact.LastName = address;
          contact.Email = address;
        }
       
        // Add if new
        if ([select count() from Contact where Email = :contact.Email] == 0) {
          contact.AccountId = account.Id;
          insert contact;
        }
      }

You can even access text and binary attachments:

 
      // Save attachments, if any
      for (Messaging.Inboundemail.TextAttachment tAttachment : email.textAttachments) {
        Attachment attachment = new Attachment();
       
        attachment.Name = tAttachment.fileName;
        attachment.Body = Blob.valueOf(tAttachment.body);
        attachment.ParentId = account.Id;
        insert attachment;
      }
      for (Messaging.Inboundemail.BinaryAttachment bAttachment : email.binaryAttachments) {
        Attachment attachment = new Attachment();
       
        attachment.Name = bAttachment.fileName;
        attachment.Body = bAttachment.body;
        attachment.ParentId = account.Id;
        insert attachment;
      }

And of course, you can access the body of an email as well. In this case we’re assuming a plain email (not an HTML one) and use the plainTextBody field:

 
      // Turn email body into note
      Note note = new Note();
     
      note.Title = email.fromName + ' (' + DateTime.now() + ')';
      note.Body = email.plainTextBody;
      note.ParentId = account.Id;
      insert note;
      …
 

Here we explicitly indicate success or failure by setting the success field of our InboundEmailResult object.

   
      …
      result.success = true;
    } catch (Exception e) {
      result.success = false;
      result.message = ‘Oops, I failed.’
    }
   
    return result;
  }
}

If a failure was indicated (if the success field is set to false) then the platform automatically rejects the inbound email and sends a reply email to the original sender containing the message specified in the message field.

That’s all it takes! Of course, we’ve written a reasonably complex class here, but there’s really only a single method to implement, and the framework makes all the bits that matter (the email addresses, the email body, the attachments and so on) very easily accessible.

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

You’ll see something like the following screen:

Creating a 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 ([email protected]) or domains (b.com) that Email Services can accept emails from. If you leave it blank, all addresses will work.
  5. Hit Save.
Completing Email Service Setup

You will see a new email address that Force.com will monitor: emails received on this address will trigger the associated Apex code.

An Email Service, ready to receive

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.

Putting It Together

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

Sending Email

Let’s now turn to outbound email. You can also have Force.com send emails on your behalf. This can happen wherever Apex logic runs, essentially in triggers, email services, Visualforce controllers, and so on.

Emails sent by Force.com can be one of two types:

  • Single emails are like regular individual emails that may go to one or more addresses (to/cc/bcc), but each of these emails has the same body.
  • Mass emails typically go to a large number of addresses (currently capped to 250 per email), with personalized message bodies.

Here are some key differences to help you choose between the two:

SINGLE EMAIL MASS EMAIL
Multiple recipients? Yes Yes
Personalized body? Yes (single body only) Yes
Special permission needed? No Yes, has to be enabled
Merge fields? Yes Yes
Personalized merge fields? Yes (only one record at a time) Yes
Templates? Yes Yes
Template possibilities? Text/HTML/Visualforce/Custom Templates Text/HTML/Custom Template

To illustrate how you can use these two email mechanisms and different templates, here are two triggers that both respond to updates of Case records by sending emails. The first sends a single email using a Visualforce template. The second sends a mass email using a text template. But first we must discuss what governor limits apply to sending email.

Outbound Email Limits

There are two sets of limits that you must consider when architecting your outbound email strategy. The first is that your org has a strict 24-hour limit around how many outbound emails can be sent in that 24-hour period. This is is a little to complex to discuss here, and is well explained in the Apex Code Developer Guide's page on execution and governor limits.

The second limit is a governor limit. Emails are sent using the Messaging.sendEmail() method. Governor limits allow no more than 10 invocations of this method "per transaction". Just as it is imperative in Apex to not invoke DML or SOQL in a for loop, it is probably even more so with sendEmail() as a mere 11 records will breach this limit.

Sending Single Emails

Now that we know the ground rules, our first trigger sends email to the contacts for the cases using a Visualforce template. The logic here happens to be inside a trigger, but can be anywhere you execute Apex.

First thing to do is get the email template ID for use in constructing our email messages. This is done by querying for the template by name (in this instance). Templates are convenient for building the messages, but they are optional: you can also directly set the message body with setHtmlBody() or setPlainTextBody(). At this time we will also create an instance of List<SingleEmailMessage> to batch up the messages we want to eventually send.

trigger EmailDemoSendSingle on Case (after insert) {

  final String template = 'EmailDemoSendSingleTemplate';
  Id templateId; 

  try {
    templateId = [select id from EmailTemplate where Name = :template].id;
  } catch (QueryException e) {
    ...handle exception if no template is retrieved, or create condition to set email body in code
  }

  List<Messaging.SingleEmailMessage> messages = new List<Messaging.SingleEmailMessage>();
  …

Next, the code will iterate over the cases in question. However, because of the need to populate related contact data there is a need to requery and populate the related contact information.

Each iteration requires instantiating Messaging.SingleEmailMessage, setting required data into that object, then adding it to the list of messages to send.

During the construction of each message, you optionally call setTargetObjectId() and setWhatId() on the message if you have merge fields in the template. If you’re using a Visualforce template (such as this example), the id in setTargetObjectId() corresponds to the recipient of the email. This will allow merge fields like {!recipient.FirstName} to resolve properly. The id in setWhatId() corresponds to the object used for the relatedTo object used in the merge fields. In this example, these correspond to a Contact and Case record respectively.

  …
  // Send single mail to contact of each updated case
  for (Case uc : [select ContactId, Contact.Email from Case where Id in :Trigger.new and HasOptedOutofEmail = false]) {

    Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage();

    message.setTemplateId(templateId);
    message.setTargetObjectId(uc.ContactId);
    message.setWhatId(uc.Id);
    …

Finally, you set the addresses (in this case just one contact per case) directly and send the email. You can specify to, cc, and bcc separately. Once complete add the new message to the list of messages to send. And "outside" of the for loop, call sendEmail() on the list.

      …
      message.setToAddresses(new String[] {uc.Contact.Email});
      messages.add(message);
    }

    Messaging.sendEmail(messages);
}

The Visualforce template is a regular Visualforce document that uses the merge fields recipient and relatedTo as explained above. This builds a simple notification body.

A Simple Template

Note the use of the special <messaging:emailTemplate> and associated Visualforce tags.

That’s it! If you create a new Case record, the trigger will fire, which will in turn send off emails to a number of contacts, each with a personalized email generated from the Visualforce template.

Mass Email

Mass email differs from single emails mainly in the way that they specify the merge fields and addresses. The following code contains a trigger that responds to Case record updates. Unlike the previous trigger, this code will email all the contacts for the Account related to the Case.

You start by creating an instance of MassEmailMessage. As with the single email case, you select the template that has the merge fields.

trigger EmailDemoSendMass on Case (after update) {
  final String template = 'EmailDemoSendMassTemplate';
  Messaging.MassEmailMessage message = new Messaging.MassEmailMessage();
 
  message.setTemplateId([select Id from EmailTemplate where Name = :template].Id);
  …
 

Unlike single emails that use just one TargetObjectId, mass emails take a list of ids through setTargetObjectIds(). Force.com will then send out individual emails to each of the addresses corresponding to the ids, also matching the id to the merge fields in template. Note though that the ids should all be of the same type (for example all Contacts, Users, or Leads) – you cannot mix them.

If you choose Contacts for the TargetObjectId (as in this example), you can also optionally specify a corresponding WhatId list to map to the template merge fields.

  … 
  // Send mass email to contacts of account associated with each updated case
  for (Case uc : Trigger.new) {
    Contact[] contacts = [select HasOptedOutofEmail, Id from Contact where AccountId = :uc.AccountId];
    Id[] targetObjectIds = new Id[] {};
    Id[] whatIds = new Id[] {};
   
    for (Contact c : contacts) {
        targetObjectIds.add(c.Id);
        whatIds.add(uc.Id);
    }
   
    message.setTargetObjectIds(targetObjectIds);
    message.setWhatIds(whatIds);
    …

Finally, you do not need to specify the addresses because Force.com will pick those up based on the TargetObjectIds list.

 
    …
    Messaging.sendEmail(new Messaging.Email[] {message});
  }
}

Here’s the corresponding text template. It generates the same body as the Visualforce template above, but note the difference in the way the two templates define the merge fields. You cannot use Visualforce templates to define mass email templates.

A Mass Email Template

That’s it! When a Case record is created and the trigger runs, a number of emails is sent out. Each email will have its own set of merge fields set, drawn from the list of IDs found in the TargetObjectIds and WhatIds lists.

Testing the Inbound Email Handler

As with any code on Force.com, you should write test cases. But how do you test the inbound email handler?

Well, it turns out to be quite simple - simply invoke the method as if the email service had invoked it. This involves setting up your own email and envelope by instantiating the correct objects. Here's a sample test class:

@IsTest
private class EmailDemoReceiveHandlerTests {

        // Create a new email and envelope object
        Messaging.InboundEmail email  = new Messaging.InboundEmail();
        Messaging.InboundEnvelope env = new Messaging.InboundEnvelope();
        
        // Set up your data if you need to
        
        // Create the email body
        email.plainTextBody = 'This should become a note';
        email.fromAddress ='[email protected]';
        String contactEmail = '[email protected]';
        email.ccAddresses = new String[] {'Jon Smith <' + contactEmail + '>'};
        email.subject = 'Dummy Account Name 123';
        
        EmailDemoReceive edr = new EmailDemoReceive();
        
        Test.startTest();
        Messaging.InboundEmailResult result = edr.handleInboundEmail(email, env);
        Test.stopTest();
        
        System.assert (result.success, 'InboundEmailResult returned a failure message');
        
        Account [] accDb = [select ID from Account where name=:email.subject];
        System.assertEquals (1, accDb.size(),'Account was not inserted');
        Contact [] cDb = [select firstname,lastname from Contact where email=:contactEmail];
        System.assertEquals (1, cDb.size(),'Contact was not inserted!');
        Contact c = CDb[0];
        System.assertEquals ('Jon', c.firstName);
        System.assertEquals ('Smith', c.LastName);
        Note [] nDb = [select body from Note where ParentID=:accDb[0].id];
        System.assertEquals (1,nDb.size(), 'A note should have been attached');
        System.assertEquals (email.plainTextBody, nDb[0].body);
        
    } 
}

The above code creates an email and envelope, as well as an instance of our email handler, EmailDemoReceive. It then invokes the handleInboundEmail method, and runs a series of tests. The tests ensure that the code behaves appropriately - in this case testing that an account was created with the subject of the email, that contacts were created for the CC field, and that a note was attached to the account with the body of the email.

As explained in How to Write Good Unit Tests, this is by no means a complete test class. For example, we don't have any test methods for negative conditions (perhaps the code misbehaves when an email is sent without a body, or when the CC list is empty, and so on). However, the above code should give you a good idea of how to create such tests for an email handler.

Summary

Force.com has all the necessary services to easily receive emails and send single or mass emails. The platform does almost all of the underlying messaging work for you. For responding to incoming emails, you simply create an inbound email handler, bind it to an email service and an email address, and you’re away. For outbound emails, you either create a single or mass email, bind that to a template, and optionally add logic to locate objects used to define the merge fields.

References

Appendix

Earlier, we noted that the EmailDemoReceive try/catch block was not sufficient for handling exceptions. The basic problem is that because we catch the exception, the Apex method as a whole "succeeds", and so a transaction doesn't roll back. As a result, database inserts that occur within that block may still be committed. If that isn't the intent, a different action may need to take place (for example, throwing an exception, or using database save points.

About the Author

Sekhar Ravinutala is a software developer/entrepreneur (worked at Oracle/Sybase). He is now the Founder/CEO of AllureFX LLC and is working on the social app Herdcall.