A blog about Salesforce CRM Configuration and development

Sunday, 30 December 2018

Send Email with Visualforce page (PDF) as an attachment using lightning component.


Sometimes Salesforce customer/user needs to send a Contract to their client and they don't want to make the Contract Terms document (pdf) manually by their employee. The Salesforce provides the standard object called Contract, which is related with Account and this Contract object keeps all the information about the Contract terms.  The customer/user wants to send an email to their client with Contracts records as an attached PDF document. In that case, we need to make the custom solution for this.

I am going to break this requirement into two part.
  1. The visualforce page which will show Contract details and it will render as PDF.
  2. The Lightning Component which will provide the user interface to enter required email fields. 
So, Let's jump into the 1st part of the requirement. The visualforce page will show the details of Contract.

ContractPDF.vfp
 <apex:page controller="ContractPDFCntrl" sidebar="false" showHeader="false" applyBodyTag="false" renderAs="PDF">  
   <html>  
     <head>  
     </head>  
     <body>  
       <table style="border-collapse: collapse; ">  
         <apex:repeat value="{!wrapperList}" var="row">  
           <tr style="border: 1px solid rgb(221, 219, 218); width:700px;">   
             <apex:repeat value="{!row.values}" var="value">  
               <td style="border: 1px solid rgb(221, 219, 218); padding: 15px; ">{!value}</td>  
               <td style="border: 1px solid rgb(221, 219, 218); padding: 15px;">  
                 {!row.values[value]}  
               </td>  
             </apex:repeat>  
           </tr>  
         </apex:repeat>  
       </table>  
     </body>  
   </html>  
 </apex:page>  
 renderAs="PDF"  
The renderAs="PDF" is an attribute of <apex:page> which is responsible for rendring the Visualforce page as pdf
Apex Controller: ContractPDFCntrl.apxc
 public class ContractPDFCntrl {  
   //WrapperList  
   public List<Wrapper> wrapperList{get;set;}  
   public ContractPDFCntrl(){  
     wrapperList = new List<Wrapper>();  
     // getting Contract record Id from page URL  
     string recordId = ApexPages.CurrentPage().getParameters().get('id');  
     Contract cont = [select id,Name,BillingAddress,Account.Name,CompanySignedId,CompanySignedDate,EndDate,ContractNumber,StartDate,  
              ContractTerm,CustomerSignedDate, CustomerSignedTitle,Description,ShippingAddress,SpecialTerms,  
              Status from Contract where id=:recordId] ;  
     for (Integer idx=0; idx<15; idx++)  
     {  
       wrapperList.add(new Wrapper());  
     }  
     if(cont.Name!=null){  
       wrapperList[0].addValue('Name',cont.Name);  
     }  
     else{  
       wrapperList[0].addValue('Name','N/A');  
     }  
     if(cont.BillingAddress!=null){  
       Address addr = cont.BillingAddress;  
       wrapperList[1].addValue('Billing Street',addr.getStreet());  
     }else{  
       wrapperList[1].addValue('Billing Street','N/A');  
     }  
     if(Account.Name!=null ){  
       wrapperList[2].addValue('Name',cont.Account.Name);  
     }else{  
       wrapperList[2].addValue('Name','N/A');  
     }  
     if(cont.CompanySignedId !=null){  
       wrapperList[3].addValue('Company Signed Id',cont.CompanySignedId);  
     }else{  
       wrapperList[3].addValue('Company Signed Id','N/A');  
     }  
     if(cont.CompanySignedDate !=null){  
       wrapperList[4].addValue('Company SignedDate',String.valueOf(cont.CompanySignedDate));  
     }else{  
       wrapperList[4].addValue('Company SignedDate','N/A');  
     }  
     if(cont.EndDate !=null){  
       wrapperList[5].addValue('EndDate',String.valueOf(cont.EndDate));  
     }else{  
       wrapperList[5].addValue('EndDate','N/A');  
     }  
     if(cont.ContractNumber !=null){  
       wrapperList[6].addValue('Contract Number',String.valueOf(cont.ContractNumber));  
     }else{  
       wrapperList[6].addValue('Contract Number','N/A');  
     }  
     if(cont.StartDate !=null){  
       wrapperList[7].addValue('StartDate',String.valueOf(cont.StartDate));  
     }else{  
       wrapperList[7].addValue('StartDate','N/A');  
     }  
     if(cont.ContractTerm !=null){  
       wrapperList[8].addValue('ContractTerm',String.valueOf(cont.ContractTerm));  
     }else{  
       wrapperList[8].addValue('ContractTerm','N/A');  
     }  
     if(cont.CustomerSignedDate !=null){  
       wrapperList[9].addValue('CustomerSignedDate',String.valueOf(cont.CustomerSignedDate));  
     }else{  
       wrapperList[9].addValue('CustomerSignedDate','N/A');  
     }  
     if(cont.CustomerSignedTitle !=null){  
       wrapperList[10].addValue('CustomerSignedTitle',String.valueOf(cont.CustomerSignedTitle));  
     }else{  
       wrapperList[10].addValue('CustomerSignedTitle','N/A');  
     }  
     if(cont.Description !=null){  
       wrapperList[11].addValue('Description',String.valueOf(cont.Description));  
     }else{  
       wrapperList[11].addValue('Description','N/A');  
     }  
     if(cont.ShippingAddress !=null){  
       Address addr = cont.ShippingAddress;  
       wrapperList[12].addValue('ShippingAddress',String.valueOf(addr.getStreet()));  
     }else{  
       wrapperList[12].addValue('ShippingAddress','N/A');  
     }  
     if(cont.SpecialTerms !=null){  
       wrapperList[13].addValue('SpecialTerms',String.valueOf(cont.SpecialTerms));  
     }else{  
       wrapperList[13].addValue('SpecialTerms','N/A');  
     }  
     if(cont.Status !=null){  
       wrapperList[14].addValue('Status',String.valueOf(cont.Status));  
     }else{  
       wrapperList[14].addValue('Status','N/A');  
     }  
   }  
   //Wrapper class  
   public class Wrapper{  
     public Map<String,string> values {get; set;}  
     // constructor  
     public Wrapper()  
     {  
       values = new Map<String,String>();  
     }  
     //Wrapper method  
     public void addValue(String Name, String Value)  
     {     //put data in values map.  
       values.put(Name,Value);  
     }  
   }  
 }  

When you preview the page it will look like the screen below.

https://yourdomain-dev-ed--c.ap7.visual.force.com/apex/ContractPDF?id=ContractId

2nd Part: Lightning Component.
SendEmailComponent.cmp
 <aura:component controller="SendEmailCntrl" implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes,force:lightningQuickAction" access="global" >  
   <aura:handler name="init" value="{!this}" action="{!c.OnLoad}"/>  
   <!-- attributes-->   
   <aura:attribute name="email" type="string"/>  
   <aura:attribute name="subject" type="string"/>  
   <aura:attribute name="body" type="string"/>  
   <aura:attribute name="cc" type="string"/>  
   <aura:attribute name="Bcc" type="string"/>  
   <aura:attribute name="mailStatus" type="boolean" default="false"/>  
   <!-- Account record Id attaribute -->  
   <aura:attribute name="recordId" type="string"/>  
   <!-- Wrapper -->  
   <aura:attribute name="WrapObj" type="wrapper"/>  
   <!-- User Info -->  
   <aura:attribute name="currentUser" type="user"/>  
   <!-- CC input TRUE?FALSE Boolean -->  
   <aura:attribute name="displayCC" type="Boolean" default="false"/>  
   <div class="slds-m-around--medium">  
     <div class="slds-container--medium">  
       <div class="slds-form--stacked">  
         <div class="slds-form-element">  
           <label class="slds-form-element__label" for="CC">From</label>  
           <div class="slds-form-element__control">  
             <ui:inputEmail class="slds-input" aura:id="email" value="{!v.currentUser.Email}" required="true" placeholder="abc@email.com" disabled="true"/>  
           </div>  
         </div>  
         <div class="slds-form-element">  
           <label class="slds-form-element__label" for="CC">To</label>  
           <div class="slds-form-element__control">  
             <ui:inputEmail class="slds-input" aura:id="email" value="{!v.email}" required="true" placeholder="abc@email.com"/>  
             &nbsp;<a onclick="{!c.showCC}">CC</a>  
           </div>  
         </div>  
         <aura:if isTrue="{!v.displayCC}">  
           <div class="slds-form-element">  
             <label class="slds-form-element__label" for="CC">Cc</label>  
             <div class="slds-form-element__control">  
               <ui:inputEmail class="slds-input" aura:id="cc" value="{!v.cc}" placeholder="abc@email.com"/>  
             </div>  
           </div>  
         </aura:if>  
         <div class="slds-form-element">  
           <label class="slds-form-element__label" for="CC">Bcc</label>  
           <div class="slds-form-element__control">  
             <ui:inputEmail class="slds-input" aura:id="Bcc" value="{!v.Bcc}" placeholder="abc@email.com"/>  
           </div>  
         </div>  
         <div class="slds-form-element">  
           <label class="slds-form-element__label" for="CC">Subject</label>  
           <div class="slds-form-element__control">  
             <ui:inputText class="slds-input" aura:id="subject" value="{!v.subject}" placeholder="Subject"/>  
           </div>  
         </div>  
         <div class="slds-form-element">  
           <label class="slds-form-element__label" for="textareaSample2">Mail Body</label>  
           <div class="slds-form-element__control">  
             <lightning:inputRichText aura:id="body" value="{!v.body}" />  
           </div>  
         </div>  
         <div class="slds-page-header">  
           Attach Contract  
         </div>  
         <table class="slds-table slds-table--bordered" style="border-right: 1px solid rgb(216, 221, 230); border-left: 1px solid rgb(216, 221, 230);border-top: 0px solid rgb(216, 221, 230);">  
           <thead>  
             <tr>  
               <th>Select</th>  
               <th>Contract Number</th>  
             </tr>  
           </thead>  
           <tbody>  
             <aura:iteration items="{!v.WrapObj}" var="w">  
               <tr>  
                 <td><ui:inputCheckbox class="myCheckbox" aura:id="check" value="{!w.check}"/></td>  
                 <td>{!w.contrct.ContractNumber}</td>  
               </tr>  
             </aura:iteration>  
           </tbody>  
         </table>  
         <br/><br/>  
         <button type="button" class="slds-button slds-button--brand" onclick="{!c.sendMail}">Send</button>  
       </div>  
     </div>  
   </div>  
   <!-- End -->  
 </aura:component>  
SendEmailComponentController.js
 ({  
   OnLoad : function(component,event,helper){  
     helper.getCurrentUser(component,event,helper);  
     var action = component.get("c.onLoad");  
     action.setParams({  
       "recordId" : component.get("v.recordId")  
     });  
     action.setCallback(this,function(response){  
       var state = response.getState();  
       if(state == 'SUCCESS'){  
         var result = response.getReturnValue();  
         console.log('Result : ### ' + JSON.stringify(result));  
         component.set("v.WrapObj", result);  
       }else{  
         console.log('something bad happed! ');  
       }  
     });  
     $A.enqueueAction(action);  
   },  
   sendMail: function(component, event, helper) {  
     //alert('**** Test');  
     var wrappers = component.get('v.WrapObj');  
     var ids=new Array();  
     alert('array size: ' +wrappers.length);  
     for (var idx=0; idx<wrappers.length; idx++) {  
       alert(wrappers[idx].check);  
       if (wrappers[idx].check) {  
         ids.push(wrappers[idx].contrct.Id);  
       }  
     }  
     var idListJSON=JSON.stringify(ids);  
     //alert(idListJSON);  
     var Email = component.get("v.email");  
     var Subject = component.get("v.subject");  
     var body = component.get("v.body");  
     var CcEmail = component.get("v.cc");  
     var BcccEmail = component.get("v.Bcc");    
     if ($A.util.isEmpty(Email) || !Email.includes("@")) {  
       alert('Please Enter valid Email Address');  
     } else {  
       helper.sendEmailHelper(component, Email, Subject, body, idListJSON,CcEmail,BcccEmail);  
     }  
   },  
   //Show CC email input  
   showCC : function(component,event,helper){  
     component.set("v.displayCC", true);  
   },  
   closeModal : function(component,event,helper){  
     //Close the modal  
     component.set("v.isOpen",false);  
   },  
 })  
SendEmailComponentHelper.js
 ({  
   sendEmailHelper: function(component, getEmail, getSubject, getbody,getContractIds,getCcEmail,getBcccEmail) {  
     // call the server side controller method to send email  
     var action = component.get("c.sendContractMail");  
     action.setParams({  
       'emailId': getEmail,  
       'subject': getSubject,  
       'emailbody': getbody,  
       'ContractIds' :getContractIds,  
       'ccEmail' : getCcEmail,  
       'bccEmail' : getBcccEmail  
     });  
     action.setCallback(this, function(response) {  
       var state = response.getState();  
       if (state === "SUCCESS") {  
         var storeResponse = response.getReturnValue();  
         //If server response return 'success' show toast message that email has been sent.  
         if(storeResponse == 'success'){  
           var toastEvent = $A.get("e.force:showToast");  
           toastEvent.setParams({  
             "title": "Success!",  
             "type": "success",  
             "message": "Email Sent Successfully!"  
           });  
           toastEvent.fire();  
           var navEvt = $A.get("e.force:navigateToSObject");  
           navEvt.setParams({  
             "recordId": component.get("v.recordId"),  
             "slideDevName": "detail"  
           });  
           navEvt.fire();  
         }  
         else{ // show error toast message  
           var toastEvent = $A.get("e.force:showToast");  
           toastEvent.setParams({  
             "title": "Success!",  
             "type": "error",  
             "message": storeResponse  
           });  
           toastEvent.fire();  
         }  
       }  
     });  
     // calling server side Apex method(This will be called asynchronously).  
     $A.enqueueAction(action);  
   },  
   getCurrentUser : function(component,event,helper){  
     var action = component.get("c.fetchUserDetails");  
     action.setCallback(this,function(response){  
       var state = response.getState();  
       if(state == 'SUCCESS'){  
         var result = response.getReturnValue();  
         console.log('result: ' + result);  
         component.set("v.currentUser", result);  
       }  
       else{  
         console.log('Something bad happend! ');  
       }  
     });  
     // calling sever side action method  
     $A.enqueueAction(action);  
   }  
 })  
Apex Controller:
 public class SendEmailCntrl {  
   @AuraEnabled  
   public static List<Wrapper> onLoad(string recordId){  
     List<Wrapper> wrapList = new List<Wrapper>();  
     Account acc = [select id,(select id,Name,ContractNumber from Contracts) from Account where id=:recordId];  
     for(Contract c: acc.contracts){  
       wrapList.add(new Wrapper(false,c));  
     }  
     //Return wrapperList  
     return wrapList;  
   }  
   @AuraEnabled   
   public static user fetchUserDetails(){  
     // query current user information   
     User oUser = [select id,Name,TimeZoneSidKey,Username,Alias,Country,Email,FirstName,LastName,IsActive   
            FROM User Where id =: userInfo.getUserId()];  
     return oUser;  
   }  
   @AuraEnabled   
   public static String sendContractMail(String emailId ,String subject ,String emailbody,String ContractIds, String ccEmail, String bccEmail){  
     system.debug('ContractIds: ' +ContractIds);  
     String SUCCESS_MSG = '';  
     String ERROR_MSG = '';  
     List<Messaging.SingleEmailMessage> mails = new List<Messaging.SingleEmailMessage>();     
     // Create mail obj  
     Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();  
     // list of people to whome email will be send  
     List<String> sendTo = emailId.split(',');  
     //sendTo.add(mMail);  
     List<String> ccTo = new List<String>();  
     if(ccEmail!='' && ccEmail!=null){  
       ccTo = ccEmail.split(',');  
     }  
     List<String> bccTo = new List<String>();  
     if(bccEmail!='' && bccEmail!=null){  
       bccTo = bccEmail.split(',');  
     }  
     // Send To    
     mail.setToAddresses(sendTo);  
     // bcc to  
     if(bccTo.size()>0)  
       mail.setBccAddresses(bccTo);  
     //cc to   
     if(ccTo.size()>0)  
       mail.setCcAddresses(ccTo);  
     //Set who the email is sent from  
     mail.setReplyTo('noreply@gmail.com'); // change it with your mail address.  
     mail.setSenderDisplayName('salesforce User');   
     // subject and email body  
     mail.setSubject(subject);  
     mail.setHtmlBody(emailbody);  
     // add email in list  
     mails.add(mail);  
     Type idArrType=Type.forName('List<Id>');  
     // selected contarctIds  
     List<Id> ids=(List<Id>) JSON.deserialize(ContractIds, idArrType);  
     //List of Emailfileattachment  
     List<Messaging.Emailfileattachment> fileAttachments = new List<Messaging.Emailfileattachment>();  
     // Map<Contract, Blob>   
     Map<Contract, Blob> bodyMap = new Map<Contract, Blob>();  
     //Attachments  
     for(Contract c: [select id,ContractNumber from Contract where id IN: ids]){  
       PageReference pdf = Page.ContractPDF;//ContractPDF is the name of vf page  
       pdf.getParameters().put('id',c.Id); //sending contract id paramater to 'ContractPDF' VF.  
       bodyMap.put(c, pdf.getContent()); // get vf page as blob.  
     }  
     for(Contract cntrct: bodyMap.keySet()){  
       // Add to attachment file list  
       Messaging.Emailfileattachment efa = new Messaging.Emailfileattachment();  
       efa.setFileName(cntrct.ContractNumber);  
       if(bodyMap.containsKey(cntrct)){  
         Blob b = bodyMap.get(cntrct);  
         efa.setBody(b);  
       }  
       efa.setContentType('application/pdf');  
       fileAttachments.add(efa);  
     }  
     mail.setFileAttachments(fileAttachments);  
     //Send email  
     try{  
       Messaging.sendEmail(mails);  
       SUCCESS_MSG = 'success';  
       return SUCCESS_MSG;  
     }  
     catch(Exception e){  
       ERROR_MSG = 'Error:'+e.getmessage();  
       return ERROR_MSG;  
     }  
   }   
 }  
Now create Quick Action button on Account.
Add this Quick Action on Account page Layout.
Output:



Hope this post will help many.
Thanks
Arun Kumar
Share:

2 comments:

  1. Hi, I am receiving error in SendEmailCntrl
    Error : Constructor not defined: [Wrapper].(Boolean, Contract)
    for this part of code:
    for(Contract c: acc.contracts){
    wrapList.add(new Wrapper(false,c)); //error
    }

    ReplyDelete
  2. Thanks a lot very much for the high quality and results-oriented help. I won’t think twice to endorse your blog post to anybody who wants and needs support about this area.
    CRM with Invoicing

    ReplyDelete

Trailhead Profile


Follow by Email

Total Pageviews

Followers

Popular Posts

Powered by Blogger.

Contact form

Name

Email *

Message *