Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

How to Attach a Dynamic PDF to a Salesforce Messaging Email Template

4.00/5 (1 vote)
23 Sep 2016CPOL2 min read 24.3K  
This tip describes how to attach a dynamic PDF to a Salesforce messaging email template.

Introduction

While it is well known how to send dynamic email attachments using APEX in Salesforce, what is not well known is how to send dynamic email attachments using an email template (i.e., messaging:emailTemplate) for use in workflow rules and email alerts. This tip describes how to attach dynamic PDFs to a Salesforce messaging email template.

How It Works

This endeavor requires several different pieces in order to work:

  • A pdf page (e.g. Invoice)
  • A class for your PDF page (e.g., InvoiceController)
  • A component to be referenced by the email template (e.g., IncludeAttachment)
  • A class for the referenced component (e.g., IncludeAttachmentController)
  • An email template containing the messaging:emailTemplate structure (e.g., Customer Invoice Email)

First, you want to create your pdf page. Here is a simple example; call this page Invoice:

XML
<apex:page controller="InvoiceController" applyHtmlTag="false" 
applyBodyTag="false" showHeader="false" sidebar="false">
<html>
<span>Here is some dynamic PDF data:  <apex:outputText 
value="{!ContactName}" escape="false"/></span>
</html>
</apex:page>

Here is the controller behind this PDF page. Call this controller InvoiceController:

Java
public class InvoiceController {

    public String ContactID {
        get{
            if(ContactID == null && 
            ApexPages.currentPage().getParameters().get('contactId') != null){
                ContactID = ApexPages.currentPage().getParameters().get('contactId');
            }
            
            return ContactID;
        }
        set;
    }

    public String ContactName {
        get{
            return [SELECT Name FROM Contact WHERE ID = :ContactID LIMIT 1].Name;
        }
        set;
    }
}

Next, you want to create a component (VisualForce or Lightening) that will be referenced by the email template. Call this component IncludeAttachments:

XML
<apex:component controller="IncludeAttachmentsController" access="global">
    <apex:attribute name="contactId"
        description="Contact Id"
        assignTo="{!contactObjectId}"
        type="Id" />

    <apex:outputText value="{!PageContents}" escape="false" />
</apex:component>

Now, we will need to create a controller called IncludeAttachmentsController:

Java
global class IncludeAttachmentsController {

/* Variables and Constants */

global String PageContents{ get; set; }
global String contactObjectId{ get; set {
    UpdateContents(value);
} }

public void UpdateContents(String contactObjectID) 
{
    try {
        PageReference pageRef = Page.Invoice;
        pageRef.getParameters().put('contactId', contactObjectID);
    
        PageContents = pageRef.getContent().toString().replace
        ('<html style="display:none !important;">', '<html>');
    } catch(exception ex) { 
        PageContents = 'An error has occurred while trying 
        to generate this invoice.  Please contact customer service.';
    }
}
}

Finally, we can create the email template itself; call this Customer Invoice Email:

XML
<messaging:emailTemplate subject="Invoice Attached" recipientType="Contact" 
 relatedToType="Contact" replyTo="your@company.com">
    <messaging:attachment renderAs="PDF" filename="Invoice.pdf">
        <c:IncludeAttachments contactId="{!relatedTo.Id}"/>
    </messaging:attachment>
    <messaging:htmlEmailBody >
    <html xmlns="http://www.w3.org/1999/xhtml">
        Please find your invoice attached.
    </html>
</messaging:emailTemplate>

Points of Interest

Notice the following line in your email template:

XML
<c:IncludeAttachments contactId="{!relatedTo.Id}"/>

This line is what calls your component with the contactId parameter. The component then calls its class, which passes the ContactId parameter to the invoice controller (i.e., InvoiceController). Notice how there is no renderAs="PDF" on the Invoice page; that is because you want this page to render as a string into the IncludeAttachmentsController. The renderAs="PDF" attribute is located on the messaging:attachment in the email template.

NOTE: If you experience an error, as in the entire email does not send in production but sends during testing, it could be that you are referencing external sites. For example, this will cause complete failure: <img src="https://www.somesite.com/someimage.png" />

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)