Save Contract As PDF And Email To Client
- abhyash
- Nov 5, 2022
- 3 min read
V1 Prepared By: Abhyash Timsina – 5 November 2022
Motivation: Say you have a requirement that you need to send a formatted PDF contract to an account’s contact via email asking for their approval. This solution will make that happen with the click of a button from the Contract record page. The look of the generated PDF will change based upon Contract Status of Draft or Activated. Note – This is a personal project and not intended for financial gain.
See this post on Medium: https://medium.com/@abhyash/save-contract-as-pdf-and-email-to-client-11c92df45d9f
My Technical Components

Source Code for ConvertToPDF Apex Class (with annotation starting with //)
/**
* Created by Abhyash Timsina on 5/11/2022.
*/
global with sharing class ConvertToPDF {
// Get Set variable declaration
public Contract con {get;set;}
public String currentRecordId {get;set;}
public ConvertToPDF() {
// Pass recordId from VisualForce page into SOQL query to get field data
currentRecordId = ApexPages.currentPage().getParameters().get('id');
con = [SELECT Id, Name, Status, ActivatedDate, StartDate, EndDate, ContractNumber, ContractTerm, ShippingAddress, Account.Name, SpecialTerms, Pricebook2.Name FROM Contract WHERE Id =: currentRecordId];
}
// Flow inputs for invocable method - contract recordId, contract Number, PDF Name and Recipient Email
public class FlowInput {
@InvocableVariable(Label='Contract RecordID' Description='Contract Record Id' Required=true)
public String recordId;
@InvocableVariable(Label='Contract Number' Description='Contract Number' Required=true)
public String contractNumber;
@InvocableVariable(Label='PDF Name' Description='PDF Name' Required=true)
public String pdfName;
@InvocableVariable(Label='Recipient Email' Description='Recipient Email' Required=true)
public String recipientEmail;
}
// Invocable method that gets called from the flow
@InvocableMethod(Label='Attach PDF' Description='Attaches PDF to Contract')
public static void attachPdf(List<FlowInput> params) {
for ( FlowInput param : params ) {
// Declaration of page reference, to reference the VF page and pass recordId
PageReference myPdf = Page.ContractPage;
myPdf.getParameters().put('id', param.recordId);
// Empty blob variable to store the pdf output data
Blob pdfBody;
// getContentAsPDF method to convert VF page to PDF
try {
pdfBody = myPdf.getContentAsPDF();
} catch (VisualforceException e) {
pdfBody = Blob.valueOf(' ');
}
// Create a file with the generated PDF's blob data and relate it with the contract
ContentVersion cv = new ContentVersion();
cv.ContentLocation = 'S';
cv.VersionData = pdfBody;
cv.Title = param.pdfName;
cv.PathOnClient = param.pdfName + '.pdf';
insert cv;
// Create an email attachment with the body of the file created earlier
Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment();
efa.setFileName(param.pdfName + '.pdf');
efa.setBody(pdfBody);
// Send Email function which passes the recipient email from flow input to the setToAddress. Other stuff you can manually configure like the plain text body, sender display name etc
Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage();
String[] sendingTo = new String[]{param.recipientEmail};
message.setToAddresses(sendingTo);
message.setSenderDisplayName('Contracts Team');
message.saveAsActivity = false;
message.subject = 'Contract: ' + param.contractNumber + ' - For your review';
message.plainTextBody = 'Hi, Please find attached contract: ' + param.contractNumber + '. Please review and advise if you wish to proceed.';
message.setFileAttachments(new Messaging.EmailFileAttachment[]{efa});
Messaging.SingleEmailMessage[] messages = new List<Messaging.SingleEmailMessage> {message};
Messaging.SendEmailResult[] results = Messaging.sendEmail(messages);
}
}
}
contractTemplate Static Resource




Source Code for ContractPage Visualforce Page (with annotation starting with //)
<!--
- Created by Abhyash Timsina on 5/11/2022.
-->
// Visualforce page that users above apex class as controller and renders if the Contract status is Activated or Draft. Different background image gets generated based upon the status.
<apex:page id="ContractPage" controller="ConvertToPDF" rendered="{!con.Status = 'Activated' || con.Status = 'Draft' }" >
<body style="font-family: Arial,serif;position:relative;text-align:center; width:100%; overflow-x:hidden; overflow-y:hidden;">
<img src="{! Case(con.Status, "Activated", $Resource.contractTemplate + '/contractTemplate/images/contract_activated.png', "Draft", $Resource.contractTemplate + '/contractTemplate/images/contract_draft.png', NULL) }" alt="Result Image"/>
<div style="font-family: Arial, serif; font-size: 11px; position: absolute; top:1%; right: 1%; left: 1%; bottom: 1%; color: white;" >
<br />
<br />
<br />
// Get Todays Date
<div style="font-family: Arial, serif;color: black;font-size: 30px">TODAYS DATE:</div>
<br />
<br />
<apex:outputText style="font-family: Arial, serif;color: orange;font-size: 30px" value="{0, date, dd/MM/yyyy}">
<apex:param value="{!TODAY()}" />
</apex:outputText>
<br />
<br />
<br />
<br />
// Passing field value from Contract Account's Name
<div style="font-family: Arial, serif;color: black;font-size: 30px">ACCOUNT:</div>
<br />
<div style="font-family: Arial, serif;color: orange; font-size: 45px">{!con.Account.Name}</div>
<br />
<br />
<br />
// Passing field value from Contract's Contract Number
<div style="font-family: Arial, serif;color: black;font-size: 30px">CONTRACT NUMBER:</div>
<br />
<div style="font-family: Arial, serif;color: orange; font-size: 45px">{!con.ContractNumber}</div>
<br />
<br />
<br />
<br />
<br />
// Passing field value from Contract's Start & End Dates
<div style="font-family: Arial, serif;color: black;font-size: 45px">Contract Start: <apex:outputText style="text-transform:uppercase; color: orange; " value=" {!con.StartDate}">
</apex:outputText></div>
<div style="font-family: Arial, serif;color: black;font-size: 45px">Contract End: <apex:outputText style="text-transform:uppercase; color: orange; " value=" {!con.EndDate}">
</apex:outputText></div>
<br />
<br />
<br />
<br />
// Passing field value from Contract's Special Terms
<div style="font-family: Arial, serif;color: black;font-size: 30px">SPECIAL TERMS:</div>
<br />
<div style="font-family: Arial, serif;color: orange; font-size: 45px">{!con.SpecialTerms}</div>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
</div>
</body>
</apex:page>
Attach PDF & Send Email Action

Attach PDF To Contract Flow

Get Contract

2. Get Contract Email

3. Attach PDF

4. Contract Generated Screen

Outcome

If Draft Status:

If Activated Status:

Package Link:
If you need help in installing and getting this working – please contact me on LinkedIn
Comments