The Salesforce flow builder currently doesn’t support sending the dynamic attachments in an email alert. For example, if you want to send all attachments attached to a record and want to them all in an email from the record then currently its not supported with the standard email component of the flow.

In this post, i will share how to create an invocable apex class and a screen flow which will get email addresses from the user and will send the email attaching all the files from the record.

Invocable apex class:

global class invocableEmailAttachment {
 
    //class to get multiple inputs from flow
    global class flowInput {                  
        @InvocableVariable(required=true)
        global String eMail;
        
        @InvocableVariable
        global String ccMail;
        
        @InvocableVariable(required=true)
        global String eSubject;
        
        @InvocableVariable
        global String ebody;
         
        @InvocableVariable
        global id currentRecordId;
        
        @InvocableVariable
        global boolean sendAttachment;
         
    }
    
    //invocable method
    @InvocableMethod(label='Email with Attachments' description='Used to send email alert along with attachments on the record.') 
    
    global static void currentRecordID(flowInput[] currentInput){      
        
        system.debug('List of Ids = '+currentInput);
        
            ID rId;
        
          for(flowInput singleID :currentInput ){
                
             //fetching record id
             rId = singleID.currentRecordId;                            
                
            system.debug('recordID= '+singleID + ' rID = '+rId);
                
            //Get the obbject of the record id
            sobject sO = rId.getSobjectType().newsobject(rId);
            
            system.debug('sO='+sO);
            
        }
        
        
          Set contentDocumentSet    = new set();  
        
          //Get all content document link where linkedEntityid=: rID. 
          for(ContentDocumentLink doc : [SELECT ContentDocumentId,ContentDocument.title,Id,LinkedEntityId,ShareType FROM ContentDocumentLink WHERE LinkedEntityId =:rID ] )  {
              contentDocumentSet.add(doc.ContentDocumentId);
        }
        
  //Get all related contentVersion file
          List contentVersionFile = [SELECT VersionData, title, FileType FROM ContentVersion WHERE ContentDocumentId IN :contentDocumentSet AND IsLatest = true];
         
        
            system.debug('Attachment List = '+ contentDocumentSet +'ConventVersion File = '+contentVersionFile);
        
        //New email message method
        Messaging.SingleEmailMessage mail= new Messaging.SingleEmailMessage();    
        
        //defining list of email attachments
        List attach= new list< Messaging.EmailFileAttachment>();
        
        
        //For each content version file get the file name, extension, version and add into the attachment list called 'attach'
        for(ContentVersion file : contentVersionFile){
             Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment();
                efa.setFileName(file.title+'.'+file.FileType);
               efa.setBody(file.VersionData);
               attach.add(efa);
            }  
        
                
              
            //List of TO email id's 
              List sendTo = new list();
                      
                        for(String emailId : currentInput[0].eMail.split(',')){
                            if(emailId !=Null){
                                sendTo.add(emailId.trim());
                            }
                            
                        }    
                  
              system.debug('send TO = '+sendTo);  
                    mail.setToAddresses(sendTo);        
              
        //List of CC email id's:
        
        if(currentInput[0].ccMail!=Null  && currentInput[0].ccMail.trim() != ''){            system.debug('ccMail '+currentInput[0].ccMail );
            List ccSendTo = new list();
            
                    for(String ccEmailId : currentInput[0].ccMail.split(',')){
                        if(ccEmailId!=Null){
                            ccSendTo.add(ccEmailId.trim());
                        }
                        
                    }
              
              mail.setCcAddresses(ccSendTo);
                    system.debug('cc : '+ccSendTo);    
        }
            
                 //Email Body
                     mail.setPlainTextBody(currentInput[0].eBody);
        
            //Email subject
              mail.setSubject(currentInput[0].eSubject);
        
            //Attachment
                   if(currentInput[0].sendAttachment ==True){
                            mail.setFileAttachments(attach);            
                    }
              
                    
            //Send Email
            Messaging.sendEmail(new Messaging.SingleEmailMessage[]{mail});
    }

 }

This class takes the user inputs from the screen flow and with a checkbox decides if the attachments needs to be send or not. Our flow will gather Send To email address, cc address, email subject and body and a send attachment checkbox from the user as input.

Screen Flow:

Activate the flow and drag and drop the flow component on your record page using the app builder. The apex class can be used for any object as the class and is not object specific.

Categories: ApexFlows

5 Comments

Dan · 28/09/2020 at 7:23 am

Hi,
That was great. If possible could you please share the test class of the code as well.

    yashadtayal · 28/09/2020 at 11:01 am

    Hi,

    Do make changes to the below test class as per your org.

    @isTest
    public class invocableEmailAttachmentTest {

    @isTest static void sendEmailSendTo() {

    List accList = new List();
    List oppList = new List();

    Account acc = new Account();
    acc.Name = ‘Knights watch’;
    insert acc;
    accList.add(acc);

    Opportunity o = new opportunity();
    o.Name = ‘Iron bank’;
    o.StageName = ‘Needs Analysis’;
    o.AccountId = acc.Id;
    o.Amount = 2000;
    o.CloseDate = system.Date.today();
    insert o;
    oppList.add(o);

    attachment att = new attachment();
    att.Name = ‘Test attachment’;
    Blob bodyBlob = Blob.valueOf(‘Unit Test Attachment Body’);
    att.Body = bodyBlob;
    att.ParentId = o.Id;
    insert att;

    string myEmail = ‘anytestEmailID@gmail.com’;
    string emailBody = ‘this is the email body’;
    string emailSubject = ‘this is subject’;
    List inputList = new List();
    List finalAttachmentList = [select id, name from Attachment where parentId =:o.Id];

    invocableEmailAttachment.flowInput input;
    input = new invocableEmailAttachment.flowInput();
    input.eMail = myEmail;
    input.ccMail = myEmail;
    input.currentRecordId = o.Id;
    input.eSubject = emailSubject;
    input.ebody = emailBody;
    inputList.add(input);

    invocableEmailAttachment.currentRecordID(inputList);

    integer invocation = limits.getEmailInvocations();

    system.assertEquals(1, invocation);
    system.assertEquals(1, finalAttachmentList.size());

    }

    }

Rodrigo Vaquero · 23/11/2020 at 11:17 am

Hi,

Thanks for the code, it looks awesome.
Question, I am declaring my variables as you did with the @InvocableVariable notation but I am not able to set any inputs on my flow when selecting the apex actions, any idea on why is this happening?

Thanks!!

    yashadtayal · 01/12/2020 at 4:06 am

    0

    Here’s the list of things you can try:

    change parameter type
    recompile all classes
    run tests
    add label and description to invocable attribute

Dan · 16/12/2020 at 6:43 pm

To confirm, this would not work with Professional Edition due to the Apex, correct?

Leave a Reply

Your email address will not be published. Required fields are marked *