Resolve 24 hour Apex email limit error in Salesforce

Sending email from Apex looks very interesting and powerful feature at first glance however by time your application evolves to more complex structure or more data, chances are very high that you will be hitting many Apex email limit related errors. As Salesforce is not mass email sending tool, it makes sense to have limits on total number of outgoing emails per 24 hours.

At a time of writing this post, mainly there would be two types of error while sending email from Apex as explained below

  1. Transaction based errors
    • We can send 100 emails per SingleEmailMessage
  2. Per day (24 hour) email limit
    • We can send 1000 emails per day

One point to note here that we can send unlimited emails to internal users including community users. More details on email limits can be found here (Salesforce governor limits)

I have seen multiple questions on Salesforce developer community on how to resolve error related to sending email per 24 hour in Apex. Below solution has been used by me for a long time and it is working to send thousands of email per day without any problem.

Let’s see how we can resolve this error with below design.

Resolve 24 hour Apex email limit error in Salesforce
Resolve 24 hour Apex email limit error in Salesforce

Email tracking Custom Object

As we are talking about sending email from Apex code, that means it is very clear that we are ready for some coding. In this case as well, whenever we want to send email , we will create a temporary record in email tracking object (Temporary Object). This object could be child of Object which needs to send email. You may or may not need this object, it completely depends on your project situation. Only reason we need object is to trigger workflow rule and have some basic informations like Email address of users to whom email should be sent. Same object can be used for reporting purpose as well to know how many emails are sent from Apex and who were recipient.

Email recipients

This is tricky situation to resolve  and this might be step because of which this solution may not work for you. Basically, even from Apex email, we need to set recipients in Email. So, instead of setting recipients in Apex email we need to set email addresses of users in temporary custom object. if we have many email recipients then we need to figure out maximum number of email fields in custom object and set email address in those fields. You may choose to have email field names as Email1, Email2 etc. We have limit of 500 fields in Enterprise and 800 fields in Unlimited edition anyway.

So till now, we have a custom Object which have information about all email addresses which needs to receive Email.

Use Workflow rule to send Emails

Now, we need to create a workflow rule on temporary custom Object saying “Whenever record is created” send email.

Till this point you may not notice how powerful this approach could be and question may be popping up in your mind that off-course we know about Workflow rule and it was not solving purpose that’s why we used Apex approach. Well, you are right but we are yet not done.

Unleashing Visualforce Email template hidden power

Whatever you can do with Apex, trigger, almost everything can be done in Visualforce email template. Again you may think that we cannot have apex controller behind it and therefore we cannot control much about output of Visualforce template. Not really; we have workaround here. We cannot have Apex controller for Visualforce Email template but we can have controller for Visualforce component and component can be easily embedded into template.

Visualforce Email templates to save
Visualforce Email templates to save

Lets run by example so that it would make more sense. Whenever any new Contact is created , Send email to newly created contact with information about all related contacts exists for that  Account.

First we need to create Visualforce component, which will get AccountId and ContactId as input and display all related contacts in tabular format

global class GetSampleAccount{

    public Id con {get;set;}
    public Id acc {get;set;}
    
    public Account accObj {get;set;}
    
    /**
    * get all sibling Contacts
    */ 
    public List<Contact> getAllContact(){
    
    
        if(acc != null)
        {
            accObj = [SELECT NAME FROM Account WHERE Id = : acc ];
            return [SELECT Id, Name, FirstName, LastName FROM Contact Where AccountId =: acc ];
        }
            
        return null;
    }
}

Component Source code:

<apex:component controller="GetSampleAccount" access="global" >
 <apex:attribute name="contactId" type="Id" description="Id of the Contact" assignTo="{!con}"/>
 <apex:attribute name="accId" type="Id" description="Id of the Account" assignTo="{!acc}"/>
 Below are all related Contacts of Account - <u> {!accObj.Name} </u>
 <table style="border: 1px solid black;border-collapse: collapse;">
 <thead> 
 <th style="border: 1px solid black"> First Name </th> 
 <th style="border: 1px solid black" > Last Name </th> 
 </thead> 
 <tbody>
 <apex:repeat value="{!allContact}" var="c" id="conRepeater"> 
 <tr> 
 <td style="border: 1px solid black" > {!c.FirstName} </td>
 <td style="border: 1px solid black" > {!c.LastName} </td> 
 </tr> 
 </apex:repeat> 
 </tbody> 
 </table>
 Thanks,
 Jitendra Zaa
</apex:component>

In order to use any component in Visualforce template, its access must be “global”. We will be using above component in Visualforce email template. All heavy lifting is done in above Visualforce component and its controller class.

To create Visualforce email template,

  • Search “Email Templates” in Quick find box.
  • Click “New Template”
  • Select type as “Visualforce”
  • In next screen, select folder where it should be saved.
  • Provide Template name
  • Select “Available for use” checkbox
  • In recipient Type, select “User”. It will not make any different to select any option because anyway email address will come from contact in my case and from temporary object in your case
  • In Related to dropdown, Select Object type from where merge fields will be used. In our case we are using Contact. However in many of cases as discussed above, it might be temporary object from where email will be initiated using workflow rules.
Creating Visualforce Email Templates
Creating Visualforce Email Templates

Click on “Save” button after all above steps. Now its time to edit template. Click on “Edit Template” and add below code

<messaging:emailTemplate subject="Welcome to Account" recipientType="Contact" relatedToType="Contact">
    <messaging:htmlEmailBody >
        <c:ParentAccount contactId="{!relatedTo.Id}" accId="{!relatedTo.Account.Id}" />
    </messaging:htmlEmailBody>
</messaging:emailTemplate>

And we are done with template. Only part remaining is to create a Workflow rule to send this email template to any email field present in Contact or temporary email tracking object.

How to send Visualforce page as an Email attachment

Sending attachment is also very easy. To send Visualforce as attachment, we need to use Component (move VF code to component) and embed it in “messaging:attachment” tag. You can refer this Salesforce documentation for sending attachment in Visualforce email template.

Lets say we want to send email and same email body should also be added as PDF file. We can change email template to look like

<messaging:emailTemplate subject="Welcome to Account" recipientType="Contact" relatedToType="Contact">
    <messaging:htmlEmailBody >
        <c:ParentAccount contactId="{!relatedTo.Id}" accId="{!relatedTo.Account.Id}" />
    </messaging:htmlEmailBody>
    
    <messaging:attachment filename="relatedContacts.pdf" renderAs="PDF">
       <c:ParentAccount contactId="{!relatedTo.Id}" accId="{!relatedTo.Account.Id}" />
    </messaging:attachment>
</messaging:emailTemplate>

As we can see in above code, we are using “messaging:attachment” tag of Visualforce email template. and content of that tag is again same Visualforce component. Read more about Visualforce Email template here

Advantage of this solution

  • Total email limit using workflow rule is 1000 x Total number of Salesforce or force.com user license.
  • It is hybrid solution where we are using Visualforce components but at the same time we are using Workflow rules which can add more actions on same transaction or switch ON – Off of functionality anytime
  • As you may create record (child record) each time so that workflow rule should execute, in that case you can have reporting capabilities as well. Currently there is no way to report on emails sent from Apex
  • You can capture other fields as well for reporting purpose
  • It also supports attachment which can have any dynamic content as discussed in this post

Trade-off

  • You may need to create extra object/record which will use your organizational storage
  • You should know in advance that at a time emails would be sent to how many users. If maximum 10 users needs to get email than temporary object needs to have 10 email fields, may be name of field could be Email1, Email2, Email3 and so on.
  • If you are not interested in tracking emails sent then this temporary object is of no use and it will use Salesforce storage. So, we need to have scheduler in place to periodically cleanup temporary object.
  • We cannot send existing attachment of record using this approach as explained in below section.

It is possible that they you may not like this solution because of some trade-off, please do share your suggestions so that we can discuss it.

Sending existing attachment (Vote this Idea) – failed attempt

I tried many ways to send attachment stored in Salesforce as an email however all attempt failed. Salesforce saves attachment in Base64 encoded form as a blob even if we are able to send attachments, its not readable. This is nearest I was able to go, still posting this code if someone try to figure it out how we can resolve this.

Visualforce component to send attachment

<apex:component access="global" Controller="GetAttachment">
     <apex:attribute name="contactId" type="Id" description="Id of the Contact" assignTo="{!con}"/>
    
    <messaging:attachment filename="{!fileToAttach.Name}" renderAs="{!fileToAttach.ContentType}">
        {!fileToAttach.Body}
    </messaging:attachment>  
</apex:component>

Yes, you are seeing right. I have used “messaging:attachment” tag in Visualforce component not in template and it works.

Apex class :

/**
 * This is controller class of component
 * */
public class GetAttachment {

    public Id con {get;set;}
    
    public Attachment fileToAttach {
        get{
            return [SELECT  ParentId,  Name,  ContentType,  Body FROM Attachment Limit 1] ;
        }
        set;
    }        
}

Visualforce Email template code :

<messaging:emailTemplate subject="Welcome to Account" recipientType="Contact" relatedToType="Contact">
    <messaging:htmlEmailBody >
        <c:ParentAccount contactId="{!relatedTo.Id}" accId="{!relatedTo.Account.Id}" />
    </messaging:htmlEmailBody>
     
    <c:SendAttachment contactId="{!relatedTo.Id}" ></c:SendAttachment> 
</messaging:emailTemplate>

This Visualforce template is sending attachment but its not in readable format.

Posted

in

by


Related Posts

Comments

4 responses to “Resolve 24 hour Apex email limit error in Salesforce”

  1. Sakthivakeswaran Avatar
    Sakthivakeswaran

    Hai Mr.Jitendra, Kindly reply when Possible for the question posted below……
    1: I could not able to find what is exact limit of single email and mass email when sending email From apex code using single and mass email methods in salesforce,

    2: And another issue with me is i could not able to find difference between single and mass emails. Kindly help me to figure out limits and difference.

  2. Nilesh Avatar
    Nilesh

    Great Work !

  3. Niran Aaric Avatar
    Niran Aaric

    Hi Jitendra, I have the same issue, but the point is i need to send attachment present in that record also along with email.. as mentioned above by you “We cannot send existing attachment of record using this approach as explained in below section.”, since this doesnt work with VF template , i have moved with trigger using SingleEmailMessage. Can i know any other feauture of overcoming this..? Or is there any other Appexchange app with which i can send Single Email message..?

    Thanks in Advance..!!!!

  4. GAURAV GARG Avatar
    GAURAV GARG

    Hi Jitendra,

    I like the above idea and we do face email limits everyday in our organization. But, in our case the email is designed at runtime based on other few objects data.

    Can we design the above solution run-time?

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Discover more from Jitendra Zaa

Subscribe now to keep reading and get access to the full archive.

Continue Reading