Find your content:

Search form

You are here

How can I capture a system.limitexception stopping my emails being sent

 
Share

In Salseforce governor limits, it states that every org is allowed to send single emails to 1000 external addresses every 24 hours. On very rare occasions, an org I work with has exceeded this limit through Apex emails on a particular busy day. Exceeding the limit prevents them from sending emails until more became available.

I appreciate that Salesforce is not a mass emailing program. However on the rare occasions when the limit is exceeded in this way, I would like there to be a way to capture exceeding this limit and redirect the emails back to the current user with an internal note instructing them to direct the messages manually (there is no limit on internal email).

Salesforce themselves suggest using the Messaging.reserveSingleEmailCapacity(count) method to determine to see if the org has the capacity to send the emails. However, this method is next to useless for this because if the emails are not available, an uncatchable system.limit exception is fired. So instead of allowing the email process to run which would cause an un-catchable exception, we can simply have this happen earlier, doesn't really help!

Does anyone have an idea about how to capture this limit break? I have heard one potential solution that involves a scheduled job updating a global setting with the latest time the job successfully ran, then using another job to read this value and react accordingly. I could do this, but given the rare occurrence of the limit exception, I would prefer not to use regular scheduled jobs in this manner.


Attribution to: Christopher Alun Lewis

Possible Suggestion/Solution #1

Now that we can catch the exception thrown by Messaging.reserveSingleEmailCapacity() so to know if the email limit has exceeded we can do this in the class..

public boolean limitErr;
public void sendMail()
{
   limitErr = false;
    try
    {
        Messaging.reserveSingleEmailCapacity(1);
    }
    catch(Exception e)
    {
        mssg = 'Mail limit for today exceeded!';
        limitErr = true;
    }

    If(!limitErr)
    {
    //send mail
    }
    else
        System.debug(mssg);
}

This is just a sample and you can modify this according to your needs and please upvote this answer if it helps.


Attribution to: Vivek Kumar

Possible Suggestion/Solution #2

I agree, it's a huge inconvenience.

My colleague has decided to use custom setting with count of emails sent so far from Apex (there's a scheduled job to reset it overnight). Definitely not an elegant solution, you need to hunt all Messaging-related code and wrap it in your own class or add a line that would increment the counter...

Feel free to upvote his idea ;) https://sites.secure.force.com/success/ideaView?id=08730000000aSLLAA2


Attribution to: eyescream

Possible Suggestion/Solution #3

Update 26th Oct: See below for a second version following comments below

I have just promoted this idea as well, I would never have imagined it to be a good design for this method to have it throw an unhandled exception, IMHO that is!

Anyway, since we are being inventive here, the following also seems to do the trick. But be aware much like the custom setting counting trick, it does not actually reserve anything for the subsequent sending of emails, as the method call is made in another VF context.

<apex:page controller="TestMessagingLimitController" action="{!check}"/>

public with sharing class TestMessagingLimitController 
{
    public PageReference check()
    {
        Integer amount = Integer.valueOf(ApexPages.currentPage().getParameters().get('amount'));
        Messaging.reserveSingleEmailCapacity(amount);       
        return null;
    }
}

You can then do this...

try
{
    PageReference checkMessages = Page.testmessaginglimit;
    checkMessages.getParameters().put('amount', '1000');
    checkMessages.getContent();
    // Success (note messages will not be reserved however)
}
catch (Exception e)
{
    // Failure
    System.debug(e.getMessage());
}

Implementation Note: If you wrap the above in your own helper method, e.g.

public static boolean checkSingleEmailCapacity(Integer amount)

You can then easily switch out this implementation with a try/catch once Salesforce allows us to catch these exceptions or provides an alternative as per the idea exchange posting.

Hope this helps!

Update: Apex REST Approach

Here is a further approach that is using a Http callout. I've left the above approach in my answer, as it has the benefit of not needing a remote site enabled, global class etc. So please make your choice! In the end if you follow the abstraction I recommended above and only call the helper method you can change your mind swiftly in the future.

@RestResource(urlMapping='/MessageLimit')
global with sharing class MessageLimit 
{
    @HttpGet
    global static void doGet() 
    {
        RestRequest req = RestContext.request;
        Integer amount = Integer.valueOf(req.params.get('amount'));
        Messaging.reserveSingleEmailCapacity(amount);               
    }

    public static boolean checkSingleEmailCapacity(Integer amount)
    {   
        Http h = new Http();
        HttpRequest req = new HttpRequest();
        req.setEndpoint(URL.getSalesforceBaseUrl().toExternalForm() + '/services/apexrest/MessageLimit?amount=' + amount);
        req.setMethod('GET');
        req.setHeader('Authorization', 'OAuth ' + UserInfo.getSessionId());
        HttpResponse res = h.send(req);
        if(res.getStatusCode() == 500) // May want to actually check the body message to be 100% sure
            return false;
        return true;
    }
}    

Thus you can now do this!

if(MessageLimit.checkSingleEmailCapacity(1001))
    System.debug('Good to go!');
else 
    System.debug('No go for launch!');              

Enjoy!


Attribution to: Andrew Fawcett
This content is remixed from stackoverflow or stackexchange. Please visit https://salesforce.stackexchange.com/questions/3752

My Block Status

My Block Content