1

I am facing Too many SOQL Error. Reason: Using "renderStoredEmailTemplate" method inside for loop that counts against SOQL query for every iteration.

 global class FlowInput {
        @InvocableVariable
        global List<id> UserId;
        
        @InvocableVariable
        global Support_Request__c getSR;
        
        @InvocableVariable
        global String EmailTemplate;
        
    }
Sample Code:
//1st Param: record Id and Template Id
//2nd Param - List of WrapperObject containing record id and multiple user ids for the corresponding record id
     global static void SendEmailMessage(map<ID, ID> SRIdemailTemplateId, List<FlowInput> varFlowInput){
           
            List<Messaging.SingleEmailMessage> msgList = new List<Messaging.SingleEmailMessage>(); 
            
            Messaging.SingleEmailMessage mail;
            
            for(FlowInput SRandTeamMemberwrapper : varFlowInput){
                for(Id userId : SRandTeamMemberwrapper.UserId){
                    System.debug('4.Number of Queries used in this apex code so far: ' + Limits.getQueries());
                    mail = Messaging.renderStoredEmailTemplate(SRIdemailTemplateId.get(SRandTeamMemberwrapper.getSR.Id), userId, SRandTeamMemberwrapper.getSR.Id);
                    mail.setTargetObjectId(userId);
                    mail.saveAsActivity  = false;
                    msgList.add(mail);  
                }
            }
            Messaging.sendEmail(msgList);
            Integer remainingInvocations = Limits.getLimitEmailInvocations() - Limits.getEmailInvocations();
            System.debug('remainingInvocations=='+remainingInvocations);

In future will be brining Batch apex. But again I do not want to have this method to be put inside nested for loop. The reason for having nested for loop is to bring the email template based upon the type of request. Any idea if there is any work around to avoid CPU limit.

2
  • Can you edit your post to describe in words what exactly this code is supposed to do, and what the input variables mean?
    – David Reed
    Jun 6, 2021 at 15:37
  • I have updated the code. The code supposed send email to the team members of the records with the corresponding email templates that would be passed as parameters in the wrapper class as above Jun 7, 2021 at 10:46

1 Answer 1

3

Well, each call to Messaging.renderStoredEmailTemplate counts as 1 SOQL call and there's no collection support for this method

Executing the renderStoredEmailTemplate method counts toward the SOQL governor limit as one query.

To avoid the SOQL limit, you need to delegate from your invocable apex to an asynchronous transaction that has greater limits and where each async transaction does not need to consume more SOQL than permitted (200)

A common pattern for this is chained queueables (each link handles, say, 50-150 emails) or batchable apex (with scope < 200)

1
  • Okay! I have two outstanding Q's 1. Since for each record there will be team members. Is there a way to avoid nested for loop to send email as shown above. As far I could see there is no option without using the "Messaging.renderStoredEmailTemplate" inside nested for loop to send email. 2. I am using auto triggered flow to call the apex class. To turn into a batch class what would be appropriate approach. Can i directly call a batch class from invokable class or need to use a scheduleBatch? Thank you Jun 11, 2021 at 9:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .