function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Kelly Logan (Raptek)Kelly Logan (Raptek) 

Getting FATAL_ERROR System.EmailException: SendEmail failed. First exception on row 0; first error: LIMIT_EXCEEDED, Too many target object ids.: []

Running on production and sandbox with an Enterprise instance (NPSP). Apex class operated fine with tests, smaller numbers of receivers. Able to send emails.

When it ran in production (with about 350 targets) it failed. When I tried manually running the class method from the Anonymous window I saw the error "FATAL_ERROR System.EmailException: SendEmail failed. First exception on row 0; first error: LIMIT_EXCEEDED, Too many target object ids.: []" in the logs.

The system is supposed to support 5,000 emails a day. I also am using Messaging.reserveMassEmailCapacity to confirm that enough resources are available to send the number of emails desired (no errors from that).

The code is copied below. Note that I tried adding the @future tag to increase limits and I used system.debug to confirm that only 400 Ids are being passed. I can't find any mention of TargetObjectId limits that are different than the daily mail limits. Also, according to the documentation if Messaging.reserveMassEmailCapacity is run without error, there is supposed to be no limit issues. Any idea what is going on here? This is holding up production work.
 
@future
    public static void duesMailNotice(List<Id> whoIds, List<Id> whatIds, String description, string templateId){
        Messaging.reserveMassEmailCapacity(whoIds.size());
        System.debug(System.LoggingLevel.ERROR,'Number of whoIds:' + whoIds.size());
        Messaging.MassEmailMessage mail = new Messaging.MassEmailMessage();
        mail.setTargetObjectIds(whoIds);
        mail.setWhatIds(whatIds);
        mail.setDescription(description);
        mail.setTemplateId(templateId);
        mail.setReplyTo('someone.else@ourdomain.org');
        Messaging.sendEmail(new Messaging.MassEmailMessage[] { mail });
    }

 
Best Answer chosen by Kelly Logan (Raptek)
Kelly Logan (Raptek)Kelly Logan (Raptek)
Ah, it's in the setTargetObjectIds method - only 250 per email.

All Answers

Kelly Logan (Raptek)Kelly Logan (Raptek)
Note also that the system is setup to use both MailChimp and Conga, but neither is being used for this.
Kelly Logan (Raptek)Kelly Logan (Raptek)
Ah, it's in the setTargetObjectIds method - only 250 per email.
This was selected as the best answer
Alain CabonAlain Cabon
Hi,

It is not a solution, just a "trick" for a first check using the workbench (free tool).

https://workbench.developerforce.com/login.php

utilities > REST Explorer > GET +  /services/data/v39.0/limits  + Execute

User-added image
The limits above are very low because it is a free developper org.

https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_limits.htm

Regards
Alain
Kelly Logan (Raptek)Kelly Logan (Raptek)
So the fix was to chunk the emails. I used 200 as a chunk size as a nice round number below 250. Note that 'duesMailNotice' is the method listed above. This method is one of those that calls it.

Since I needed to run a for loop anyway to set the whoIds and whatIds lists, I used an SOQL query to create the list of Opportunities to run through, set a counter variable (i) and check every cycle through to see if 200 entries have been added to the lists yet. Once 200 is reached the email method is called and the counter and lists are cleared to be ready for the next group. The last line calls the mail method again if there are any entries left that haven't been sent yet. The if statement at the front makes sure that the mail method is called only if there is at least one entry to mail, which accounts for the query finding no Opportunity rows and the possibility that the number of rows returned was exactly divisible by 200.

Open to more elegant solutions if anyone has advice or just wants to chat about this for a bit. :^)
public static void findDuesLate(){
        // Get list of late, unpaid (pledged) Dues payments for this month, with related Account info
        // Note that due to limit on # of addressees per mass email (250) this code sends lists of 200 at a time.
        
        Integer i = 0;
        List<Id> whoIds = new List<Id>();
        List<Id> whatIds = new List<Id>();
        for (Opportunity o :[select Id,Account.npe01__One2OneContact__c
                                                from Opportunity
                                                where RecordType.Name = 'Program Dues' and
                                                StageName = 'Pledged' and
                                                CloseDate = THIS_MONTH 
                            ]) {
            i = i + 1;
            whoIds.add(o.Account.npe01__One2OneContact__c);
            whatIds.add(o.Id);
            if (i >=200) {
                duesMailNotice(whoIds,whatIds,LATE_NOTE,tMap.get(LATE_NOTE));
                whoIds.clear();
                whatIds.clear();
                i = 0;
            }
     	}
        //And one last call to catch any stragglers 
	    if (i>0) duesMailNotice(whoIds,whatIds,LATE_NOTE,tMap.get(LATE_NOTE));
    }