BlogSalesforce

How to Avoid Governor Limits with sendEmail in Apex

By July 24, 2009 September 10th, 2019 13 Comments

You can send emails programmatically in Apex, but if you’re not careful you can hit the measly governor limit of 10 in no time at all. You see, although your outbound email limit is 1000 with Apex, only a total of 10 sendEmail method calls are allowed in each context.

Obviously the way to avoid this is to gather up all emails you want to send and call the sendEmail method once from your Apex context. When passing an argument to the sendEmail method it must be of type Email. However, in order for each email to be a unique, (assuming you want that), they need to be of type SingleEmailMessage. If you don’t desire uniqueness, you may use the MassEmailMessage type. These objects all belong to a native Apex class called Messaging.

Let’s go through some code to illustrate some techniques —

public void sendTheEmail( String[] bunchOfAddresses, String[] bunchOfSubjectTags, String[] bunchOfMsgBodys, Integer numberOfSeparateEmails ) {
Messaging.SingleEmailMessage [] theEmails = new List();
for( Integer i = 0; i < numberOfSeparateEmails; i++ ){
String[] toAddress = new List(); // setToAddresses will only accept a List (array)
toAddress.add(bunchOfAddresses.get(i));
String subjectTag = bunchOfSubjectTags.get(i);
String msgBody = bunchOfMsgBodys.get(i);

Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setToAddresses( toAddress ); // only takes a List (array) as noted above
mail.setReplyTo( replyAddress );
mail.setSenderDisplayName('My Company Email');
mail.setSubject(subjectTag);
mail.setPlainTextBody( msgBody );

theEmails.add(mail);
}

Now let’s populate an array of Email objects with each of our SingleEmailMessage objects.
Note: you can’t just pass the full SingleEmailMessage array. You MUST add each element separately.

Messaging.Email[] allMails = new List();
for( Integer j = 0; j < theMails.size(); j++ ){
allMails.add(theMails.get(j));
}

Now we can make the sendEmail call and pass in the array of Email objects

Messaging.SendEmailResult[] results = Messaging.sendEmail( allMails );

Always good to check for errors. So we use the object SendEmailError’s methods and build a little report (String)

Messaging.SendEmailError[] errors = new List();
for( Messaging.SendEmailResult currentResult : results ) {
errors = currentResult.getErrors();
if( null != errors ) {
for( Messaging.SendEmailError currentError : errors ) {
emailErrorReport = emailErrorReport + '(' + currentError.getStatusCode() + ') ' + currentError.getMessage() + 'r' ;
}
}
}

Well that’s one way to handle the programmatic sending of email in Apex.

Hope it makes your cloud computing less cloudy ~ ~ ~

Tom Burre

Tom Burre

Tom specializes in Saleforce.com. When not helping clients build custom Force.com applications or enhance Salesforce CRM functionality, Tom can be found toying with strings of the tennis, musical and of course "type" variety.

13 Comments

  • Avatar Vikram Nanduri says:

    Amazing, this code will help me lot…Thanks for posting it

  • Avatar John Mills says:

    Helped me get around the 1000 outbound email limit as well. I just set the TargetObjectId in each Email object of the array. No need to use MassEmail or a tempate…complete autonomy. Just what I needed. Thanks!!!

  • Avatar Jason Beck says:

    Great code. Helped me work around the 10 email limit for a trigger.

  • Avatar Dips says:

    John,

    How you used this to get around the 1000 outbound email limit?

  • Avatar Flor says:

    You are the best

  • Avatar Suneel Kumar Mishra says:

    Hi,
    Please help me for the following queries
    On button click from Account i have opened a vf page with all related contact to that Account, now on selected contact from VF page i have to send email on Button Click from Page. Initially i have used Single Email method.

    for(Contact conObj : selectContactList) {
    Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
    mail.setTargetObjectId(conObj.id);
    mail.setWhatId(conObj.AccountId);
    mail.setUseSignature(false);
    mail.setTemplateId(templateId);
    mail.setToAddresses(new String[] {conObj.Email});
    mailList.add(mail);
    }
    Messaging.sendEmail(mailList); sending email

    In this case if mailList Contains 1000 different email address. then will salesforce send 1000 email (i am on EE).

    some folks is saying i am testing this with same email address that why it is working in case of 1000 different email address it will fail, and saying use Mass email.

    in mass email case “setTemplateId(templateId)” limit 250 is occurring. Please help me regarding this.

  • Avatar Chirag Mehta says:

    This didn’t work for me, still getting single email limit exceeded error. Is there anything I’m missing? Sending single email message to n contacts and its ending up in SINGLE_EMAIL_LIMIT_EXCEEDED error.

  • Avatar Farrah Bannister says:

    Hello Chirag,

    I discussed your post with the team and was able to get some feedback; if the issue is persisting due to the template, it may be best to work without one. Please see below.

    Best – Farrah

    They can set an HTML body or a String body, as shown in the Docs:

    • setHtmlBody(String) 
      Optional. The HTML version of the email, specified by the sender. The value is encoded according to the specification associated with the organization. You must specify a value for setTemplateIdsetHtmlBody, orsetPlainTextBody. Or, you can define both setHtmlBody and setPlainTextBody.
    • setPlainTextBody(String) 
      Optional. The text version of the email, specified by the sender. You must specify a value for setTemplateIdsetHtmlBody, or setPlainTextBody. Or, you can define both setHtmlBody and setPlainTextBody.

    Here is the link the full docs:

    https://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_email_outbound_single.htm

    The only other thing is, they should also not use the call to setTagetObjectId

    So, the solution:

    Don’t call setTemplateId

    Don’t call setTagetObjectId

     

    Do call setHtmlBody or setPlainTextBody

  • Avatar Russell says:

    Just used this approach and it saved me so much time. Thanks

  • Avatar Sandeep Chaudhary says:

    I am getting this error : SINGLE_EMAIL_LIMIT_EXCEEDED, Failed to send email: [] while using this approach. Please help me out. Below is the code :::

    public void sendmail()
    {

    String query = ‘SELECT Id,E_mail_Id__c,Name FROM Saint__c WHERE E_mail_Id__c != null’;
    system.debug(‘Query is : ‘+query);
    List saintList = database.query(query);
    system.debug(‘saintList is :: ‘+saintList);
    List toList = new List();
    List subjectList = new List();
    List messageList = new List();
    Map IdToName = new Map();
    Map IdToEmail = new Map();
    for(Saint__c s : saintList){
    toList.add((String)s.get(‘E_mail_Id__c’));
    IdToName.put((Id)s.get(‘Id’),(String)s.get(‘Name’));
    IdToEmail.put((Id)s.get(‘Id’),(String)s.get(‘E_mail_Id__c’));
    }

    for(Id i : IdToName.keySet()){
    subjectList.add(‘Sant Nirankari Magazine Subscription’);
    String msg = ‘My text here’;
    messageList.add(msg);
    }

    system.debug(‘To list is :: ‘+toList.size());
    system.debug(‘subjectList is :: ‘+subjectList.size());
    system.debug(‘messageList is :: ‘+messageList.size());
    sendTheEmail(toList, subjectList, messageList, toList.size());

    }

    public void sendTheEmail( String[] bunchOfAddresses, String[] bunchOfSubjectTags, String[] bunchOfMsgBodys, Integer numberOfSeparateEmails ) {
    Messaging.SingleEmailMessage [] theEmails = new List();
    for( Integer i = 0; i < numberOfSeparateEmails; i++ ){
    String[] toAddress = new List(); // setToAddresses will only accept a List (array)
    toAddress.add(bunchOfAddresses.get(i));
    String subjectTag = bunchOfSubjectTags.get(i);
    String msgBody = bunchOfMsgBodys.get(i);

    Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
    mail.setToAddresses( toAddress ); // only takes a List (array) as noted above
    mail.setReplyTo( ‘sandeepchaudhary.er@gmail.com’ );
    mail.setSenderDisplayName(‘SNM Bangalore’);
    mail.setSubject(subjectTag);
    mail.setPlainTextBody( msgBody );

    theEmails.add(mail);
    }

    Messaging.Email[] allMails = new List();
    for( Integer j = 0; j < theEmails.size(); j++ ){
    allMails.add(theEmails.get(j));
    }

    Messaging.SendEmailResult[] results = Messaging.sendEmail( allMails );
    system.debug('results is :: '+results);
    String emailErrorReport;
    Messaging.SendEmailError[] errors = new List();
    for( Messaging.SendEmailResult currentResult : results ) {
    errors = currentResult.getErrors();
    if( null != errors ) {
    for( Messaging.SendEmailError currentError : errors ) {
    emailErrorReport = emailErrorReport + ‘(‘ + currentError.getStatusCode() + ‘) ‘ + currentError.getMessage() + ‘\r’ ;
    }
    }
    system.debug(’emailErrorReport is :: ‘+emailErrorReport);
    }

    }

  • Damien Phillippi Damien Phillippi says:

    @Sandeep It means you hit the email limits for the day. You have to wait until the limits refresh

  • Avatar Prasad avala says:

    What a lovely approach….Saved my time and fixed the issue without raising Limits…
    @John Mills, your response helped me to fix my 1000 emails limit as well…

  • Avatar AT says:

    Thank you for the code. It helped me !!!

Leave a Reply

Need to adjust your business processes quickly? We're helping clients use technology to keep their teams productive and running smoothly in these times of uncertainty. Our team can guide yours if you need help in these areas.

Talk to a Consultant