0

I am receiving the following error when I run the below apex invocable method in my flow:

An Apex error occurred: System.CalloutException: You have uncommitted work pending. Please commit or rollback before calling out

I believe what is happening here is that As of Winter '16, the PageReference getContent() method is treated as a callout.

I am struggling to understand how I can perform this action in a future context. My idea is to set the entire invocable method in a future context, but I am not sure if that is the best solution here.

/**
 * @description       : 
 * @author            : ChangeMeIn@UserSettingsUnder.SFDoc
 * @group             : 
 * @last modified on  : 05-18-2022
 * @last modified by  : ChangeMeIn@UserSettingsUnder.SFDoc
**/
global class SendAdvancedEmail {
@InvocableMethod(label='Send Advanced Email')
global static List <Results> SendAdvancedEmail(List<Requests> requests) {



    List<Results> results = new List<Results>();
    List<Messaging.SingleEmailMessage> singleEmailList = new List<Messaging.SingleEmailMessage>();

    for (Requests curRequest : requests) 
    {
        Set<Id> contentDocumentIds = new Set<Id>();
        Set<Id> reportIds = new Set<Id>();
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        List<Messaging.EmailFileAttachment> attachments = new List<Messaging.EmailFileAttachment>();
            if (curRequest.reports != null)
             {
                for (Report report : curRequest.reports) 
                {
                    reportIds.add(report.Id);
                }
                // Add reports as attchments
                attachments.addAll(addReportsAsEmailAttachment(reportIds));

            }

        // Create a new single email message object
        // that will send out a single email to the addresses in the To, CC & BCC list.

        // Assign the addresses for the To and CC lists to the mail object.
        mail.setToAddresses(curRequest.toAddresses);
        mail.setCcAddresses(curRequest.ccAddresses);
        mail.setBccAddresses(curRequest.bccAddresses);     
        mail.setSenderDisplayName(curRequest.senderDisplayName); 
        mail.setReplyTo(curRequest.replyEmailAddress);      
        mail.setSubject(curRequest.subject);
        mail.setReplyTo(curRequest.replyEmailAddress);
        mail.setHtmlBody(curRequest.HTMLbody);
        mail.setPlainTextBody(curRequest.plainTextBody);


        singleEmailList.add(mail);




    }

    if (singleEmailList != null && singleEmailList.size() > 0)
    {
        Results result = new Results();
        List<Messaging.SendEmailResult> emailResults = new List<Messaging.SendEmailResult>();
        emailResults = Messaging.sendEmail(singleEmailList, false);


        for(Messaging.SendEmailResult emailResult : emailResults)
        {


            if(!emailResult.IsSuccess()) 
            {                 
                result.isSuccess = false;   
                List<Messaging.SendEmailError> errors = emailResult.getErrors();

                if (errors.size() > 0){
                    result.errors = errors[0].getMessage();
                    result.statusCode = String.valueOf(errors[0].getStatusCode());
                    result.fields = errors[0].getFields();

                }                   
            } else{
                result.isSuccess = true;
            }
        }
    }





    return results;
}


global static List<Messaging.EmailFileAttachment> addReportsAsEmailAttachment(Set<Id> reportIDs)
{
    List<Report> reportList = [SELECT Id,DeveloperName,Name FROM Report where Id in :reportIDs];

    String reportId = (String)reportList.get(0).get('Id');

    //Get Report Name
    string reportName=(String)reportList.get(0).get('Name');

    //get instance Url
    String instanceName = URL.getSalesforceBaseUrl().toExternalForm();

    string url=instanceName+'/servlet/PrintableViewDownloadServlet?isdtp=p1&reportId='+reportId;

    ApexPages.PageReference objPage = new ApexPages.PageReference(url);
    Messaging.SingleEmailMessage email=new Messaging.SingleEmailMessage();

    Messaging.EmailFileAttachment objMsgEmailAttach = new Messaging.EmailFileAttachment();
    objMsgEmailAttach.setFileName(reportName+'.csv');
    if(Test.isRunningTest()) { 
        objMsgEmailAttach.setBody(blob.valueOf('Unit.Test'));
    }else{
        objMsgEmailAttach.setBody(objPage.getContent());
    }
    objMsgEmailAttach.setContentType('text/csv');

    List<Messaging.EmailFileAttachment> attachments=new List<Messaging.EmailFileAttachment>();
    attachments.add(objMsgEmailAttach);


    return attachments;
}


global class Requests {
    @invocableVariable(label='To Addresses' required=true)
    global String[] toAddresses;

    @invocableVariable(label='CC Addresses' )
    global String[] ccAddresses;

    @invocableVariable(label='BCC Addresses' )
    global String[] bccAddresses; 


    @invocableVariable(label='Subject' required=true)
    global String subject;        

    @invocableVariable(label='Email HTML Body')
    global String HTMLbody;

    @invocableVariable(label='Email Plain Text Body')
    global String plainTextBody;

    @invocableVariable(label='Sender Display Name' )
    public String senderDisplayName;

    @invocableVariable(label='Sender Email Address' required=true)
    public String senderEmailAddress;

    @invocableVariable(label='Reply Email Address')
    public String replyEmailAddress;

    @invocableVariable(label='List of Content Documents (NOT CURRENTLY IN USE)')
    global List<ContentDocumentLink> contentDocuments;

    @invocableVariable(label='List of Reports')
    global List<Report> reports;



}

global class Results {

    @InvocableVariable(label='Succesfully Sent')
    global boolean isSuccess;

    @invocableVariable(label='Error Messages')
    public String errors;

    @invocableVariable(label='Status Code')
    public String statusCode;

    @invocableVariable(label='Error Fields')
    public List<String> fields;

}

}

Matthew Metros
  • 453
  • 6
  • 21
  • Have you checked https://salesforce.stackexchange.com/questions/100167/how-to-mix-getcontentaspdf-calls-with-dml? – metasync May 18 '22 at 17:15
  • 1
    If your flow (or anything that called the flow) has done DML, then you are right, the getContent() is considered a callout and can't follow the DML in the same transaction. See if you can use Async Flows (introduced Winter 22)? – cropredy May 18 '22 at 19:21

0 Answers0