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!
Please check the below links for SaveResult class.
http://www.salesforce.com/us/developer/docs/dbcom_apex250/Content/apex_dml_insert.htm
https://www.salesforce.com/us/developer/docs/apexcode/Content/apex_methods_system_database_saveresult.htm
Here is the code that I executed in the Developer Console.
This code is trying to insert two users without any mandatory information being populated.
List<User> userList = new List<User>();
User usr1 = new User();
User usr2 = new User();
userList.add(usr1);
userList.add(usr2);
Database.SaveResult[] srList = Database.insert(userList,false);
for (Database.SaveResult sr : srList) {
if (sr.isSuccess()) {
// Operation was successful, so get the ID of the record that was processed
System.debug('Successfully inserted record. Record ID: ' + sr.getId());
}
else {
// Operation failed, so get all errors
for(Database.Error err : sr.getErrors()) {
System.debug('The following error has occurred.');
System.debug(err.getStatusCode() + ': ' + err.getMessage());
System.debug('User fields that affected this error: ' + err.getFields());
}
}
}
And the debug log shows :
04:11:35.077 (77119261)|USER_DEBUG|[16]|DEBUG|The following error has occurred.
04:11:35.077 (77130186)|SYSTEM_METHOD_EXIT|[16]|System.debug(ANY)
04:11:35.077 (77140071)|STATEMENT_EXECUTE|[17]
04:11:35.108 (108619368)|HEAP_ALLOCATE|[17]|Bytes:12
04:11:35.108 (108715273)|SYSTEM_METHOD_ENTRY|[17]|String.valueOf(Object)
04:11:35.108 (108772014)|HEAP_ALLOCATE|[17]|Bytes:22
04:11:35.108 (108800383)|SYSTEM_METHOD_EXIT|[17]|String.valueOf(Object)
04:11:35.108 (108812589)|HEAP_ALLOCATE|[17]|Bytes:2
04:11:35.108 (108848157)|HEAP_ALLOCATE|[17]|Bytes:160
04:11:35.108 (108870279)|HEAP_ALLOCATE|[17]|Bytes:184
04:11:35.108 (108891551)|SYSTEM_METHOD_ENTRY|[17]|System.debug(ANY)
04:11:35.108 (108901794)|USER_DEBUG|[17]|DEBUG|REQUIRED_FIELD_MISSING: Required fields are missing: [Username, LastName, Email, Alias, CommunityNickname, TimeZoneSidKey, LocaleSidKey, EmailEncodingKey, ProfileId, LanguageLocaleKey]
04:11:35.108 (108910963)|SYSTEM_METHOD_EXIT|[17]|System.debug(ANY)
04:11:35.108 (108922676)|STATEMENT_EXECUTE|[18]
04:11:35.108 (108932423)|HEAP_ALLOCATE|[18]|Bytes:41
04:11:35.108 (108963459)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:44
04:11:35.108 (108998846)|HEAP_ALLOCATE|[18]|Bytes:44
04:11:35.109 (109033987)|SYSTEM_METHOD_ENTRY|[18]|String.valueOf(Object)
04:11:35.109 (109072186)|HEAP_ALLOCATE|[18]|Bytes:131
04:11:35.109 (109098377)|SYSTEM_METHOD_EXIT|[18]|String.valueOf(Object)
04:11:35.109 (109117485)|HEAP_ALLOCATE|[18]|Bytes:172
04:11:35.109 (109136721)|SYSTEM_METHOD_ENTRY|[18]|System.debug(ANY)
04:11:35.109 (109145242)|USER_DEBUG|[18]|DEBUG|User fields that affected this error: (Username, LastName, Email, Alias, CommunityNickname, TimeZoneSidKey, LocaleSidKey, EmailEncodingKey, ProfileId, LanguageLocaleKey)
Best Answer
You need to use
Database.insert()
method and get results by usingDatabase.SaveResult
.Also, have a look at the DML parameter
optAllOrNone
documented here. if you want to roll back the operation in case 1 record fails.Example code: