Add Recipe

  

Recipes by Category

App Distribution (13) Bundle logic, interface and services for distribution. App Logic (52) The Apex programming language, workflow and formulas for logic. Collaboration (7) The Salesforce Chatter collaboration platform. Database (29) Data persistence, reporting and analytics. Integration (57) Web Service APIs and toolkits for integration. Security (22) Platform, application and data security. Tools (17) Force.com tooling User Interface (38) Visualforce MVC and metadata-drive user interfaces. Web Sites (13) Public web sites and apps with optional user registration and login.
Beta Feedback
Cookbook Home » An Email Utility Class to Avoid Boilerplate Code

An Email Utility Class to Avoid Boilerplate Code

Post by Anup Jadhav  (2010-09-10)

Status: Unverified
Level: novice

Taking a cue from the Java API best practices from the revered book 'Effective Java' by Joshua Bloch, I am going to use the Builder pattern[Chapter 2, Item 2] instead of creating one method with a long list of (mostly optional) parameters. This pattern also simulates named optional parameters as found in Ada and Python. As a implementer, it gives us the flexibility to add new parameters without breaking the existing use of it's methods. Another advantage of the Builder pattern is that the developer using this util class/method doesn't need to remember the order of the parameters.

Problem

This class will replace the boiler plate code to send emails in Apex.

Solution

Add this class to your Organizations Util class, or add it as a standalone class.

 public class EmailUtil {
        private Messaging.SingleEmailMessage singleEmailMessage;
        private final List<String> toAddresses;
        
        //optional parameters set to default        
        private String subject = '';
        private String htmlBody = ''; 
        private Boolean useSignature = false;
        private List<Messaging.EmailFileAttachment> fileAttachments = null;
        //defaults to current user's first name + last name
        private String senderDisplayName = UserInfo.getFirstName()+' '+UserInfo.getLastName();
        //get the current user in context
        User currentUser = [Select email from User where username = :UserInfo.getUserName() limit 1];        
        //replyTo defaults to current user's email 
        private String replyTo = currentUser.email;
        private String plainTextBody = '';
        
        public EmailUtil(List<String> addresses) {
            this.toAddresses = addresses;
        }
        
        public EmailUtil senderDisplayName(String val) {
            senderDisplayName = val;
            return this;
        }
        
        public EmailUtil subject(String val) {
            subject = val;
            return this;
        }
        
        public EmailUtil htmlBody(String val) {
            htmlBody = val;
            return this;
        }
        
        public EmailUtil useSignature(Boolean bool) {
            useSignature = bool;
            return this;
        }
        
        public EmailUtil replyTo(String val) {
            replyTo = val;
            return this;
        }
        
        public EmailUtil plainTextBody(String val) {
            plainTextBody = val;
            return this;
        }
        
        public EmailUtil fileAttachments(List<Messaging.Emailfileattachment> val) {
            fileAttachments = val;
            return this;
        }
        
        //where it all comes together
        //this method is private and is called from sendEmail()
        private EmailUtil build() {
            singleEmailMessage = new Messaging.SingleEmailMessage();
            singleEmailMessage.setToAddresses(this.toAddresses);
            singleEmailMessage.setSenderDisplayName(this.senderDisplayName);
            singleEmailMessage.setSubject(this.subject);
            singleEmailMessage.setHtmlBody(this.htmlBody);
            singleEmailMessage.setUseSignature(this.useSignature);
            singleEmailMessage.setReplyTo(this.replyTo);
            singleEmailMessage.setPlainTextBody(this.plainTextBody);
            singleEmailMessage.setFileAttachments(this.fileAttachments);
            return this;
        }
        
        //send the email message
        public void sendEmail() {
               try {
                   //call build first to create the email message object
                   build();
                   Messaging.sendEmail(new Messaging.SingleEmailMessage[] { singleEmailMessage });
               } catch (Exception ex) {
                   throw new GenericException('There was a problem while calling Messaging.sendEmail()');
               }                
        }    
            
    } 
 

The code is self-explanatory. The GenericException in the catch clause is optional, you could simply return if you don't want to throw an exception.

 //custom exception		
 public class GenericException extends Exception{
		
 }

Discussion

You can then use this class in your code as follows:
   List<String> toAddresses = new List<String> {'john.doe@acme.org'};
   String replyToAddress = 'john.duh@acme.org';
   //use the new util class to send an email
   EmailUtil emailUtil = new EmailUtil(toAddresses);
   //send plain text body
   emailUtil.plainTextBody('Bilbo Bagginses has stolen our Preciousssss!!')
				 .senderDisplayName('Gollum Gollum')
				 .replyTo(replyToAddress)
				 .sendEmail();
   //send html body
   emailUtil = new EmailUtil(toAddresses);
   emailUtil.htmlBody('I want my Ring back Frodo Baggins.')
				 .senderDisplayName('Saurons Eye')
				 .subject('One Ring to Rule them all')
				 .useSignature(true)
				 .replyTo(replyToAddress)
				 .sendEmail();
As shown in the example above, the code is more readable, and the boiler plate code required to create and send emails has been reduced to 2 lines.

Share

Recipe Activity - Please Log in to write a comment

@larkinrichards wow, you've extended my recipe and made it more comprehensive. I like it. Did you try to submit it to the cookbook? I'd recommend calling it EmailUtil ++  Definitely a thumbs up from me. :)

by Anup Jadhav  (2011-06-19)

Thanks, this class was very useful for me.

I made a number of revisions to this code in order to facilitate behavior testing of triggers that send email, and I also added some features to facilitate sending bulk emails.  I posted my revised version in the discussion forums here(4th post in thread): http://boards.developerforce.com/t5/Apex-Code-Development/Behavior-testing-a-sendEmail-statement/m-p/284331/highlight/false#M49675

by larkinrichards  (2011-06-01)

Worked like a charm -- needed to add a method to retrieve object related attachments but other than that it works great.

voted as verified by inacloud  (2011-05-18)

Thanks Anup!

by Ping Pong  (2011-05-18)

I'm using this recipe. Thanks

by Ignacio Muino  (2011-05-18)

Great Sample!

by Ping Pong  (2011-05-18)

used the recipe in our production environment, and so far haven't had any issues.

voted as verified by TMGSFDev  (2010-12-09)

Hi, does anyone know how to divert the whole email in "Active History " to "Notes & Attachment" in the custom fields? Thanks.

by Yang Manli  (2010-11-03)

That's a good Idea, Mark!
I'll update the code and re-post it.

by Anup Jadhav  (2010-11-02)

Very nice use of chaining :-)

If you wanted to simplify this, you could:
Make the build() method private and have the sendEmail() method call build() since that appears to be the only time you'd ever want to build the email.

by Mark Merrill  (2010-10-21)

this is a great sample of genericizing commonly used code to provide better interfaces to the logic than the platform does by default.

voted as verified by paul-lmi  (2010-10-17)

X

Vote to Verify a Recipe

Verifying a recipe is a way to give feedback to others and broaden your own understanding of the capabilities on Force.com. When you verify a recipe, please make sure the code runs, and the functionality solves the articulated problem as expected.

Please make sure:
  • All the necessary pieces are mentioned
  • You have tested the recipe in practice
  • Have sent any suggestions for improvements to the author

Please Log in to verify a recipe

You have voted to verify this recipe.