Create and Email a PDF with Salesforce.com
July 16th, 2010
This is a continuation of my post a couple of days ago, Attach a PDF to a Record in Salesforce, and shows how to dynamically generate a PDF and attach it to an email. The code is fairly similar and has the same issue with testing the PageReference getContent() method.
You can run this demo at my developer site.
PdfEmailer Visualforce Page
The Visualforce page simply allows the user to enter their email address and select a sample Account from the picklist. This is Account that is passed to the PdfGeneratorTemplate Visualforce page to generate the PDF.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <apex:page controller="PdfEmailController">
<apex:sectionHeader title="PDF Example" subtitle="Email a PDF"
description="Example of how to email a dynamically generated PDF."/>
<apex:form >
<apex:pageMessages />
<apex:pageBlock title="PDF Input">
<apex:pageBlockButtons >
<apex:commandButton action="{!sendPdf}" value="Send PDF"/>
</apex:pageBlockButtons>
<apex:pageBlockSection >
<apex:pageBlockSectionItem >
<apex:outputLabel value="Email to send to" for="email"/>
<apex:inputText value="{!email}" id="email"/>
</apex:pageBlockSectionItem>
<apex:pageBlockSectionItem >
<apex:outputLabel value="Account" for="account"/>
<apex:selectList value="{!accountId}" id="account" size="1">
<apex:selectOptions value="{!accounts}"/>
</apex:selectList>
</apex:pageBlockSectionItem>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
</apex:page> |
PdfEmailerController
The Controller passes the Account ID that the user entered as a parameter for the Visualforce page being generated. It let creates the attachment from the PDF content. The Body of the attachment uses the Blob returned from the PageReference’s getContent method. You could also use the getContentAsPDF method which always returns the page as a PDF, regardless of the
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | public with sharing class PdfEmailController {
public ID accountId {get;set;}
public String email {get;set;}
public List<SelectOption> accounts {
get {
if (accounts == null) {
accounts = new List<SelectOption>();
accounts.add(new SelectOption('0017000000LgRMb','United Oil & Gas Corp.'));
accounts.add(new SelectOption('0017000000LgRMV','Burlington Textiles Corp of America'));
}
return accounts;
}
set;
}
public PageReference sendPdf() {
PageReference pdf = Page.PdfGeneratorTemplate;
// add parent id to the parameters for standardcontroller
pdf.getParameters().put('id',accountId);
// the contents of the attachment from the pdf
Blob body;
try {
// returns the output of the page as a PDF
body = pdf.getContent();
// need to pass unit test -- current bug
} catch (VisualforceException e) {
body = Blob.valueOf('Some Text');
}
Messaging.EmailFileAttachment attach = new Messaging.EmailFileAttachment();
attach.setContentType('application/pdf');
attach.setFileName('testPdf.pdf');
attach.setInline(false);
attach.Body = body;
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setUseSignature(false);
mail.setToAddresses(new String[] { email });
mail.setSubject('PDF Email Demo');
mail.setHtmlBody('Here is the email you requested! Check the attachment!');
mail.setFileAttachments(new Messaging.EmailFileAttachment[] { attach });
// Send the email
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.INFO, 'Email with PDF sent to '+email));
return null;
}
} |
PdfGeneratorTemplate Visualforce Page
This is the Visualforce page that is generated in the Controller. It simply uses the StandardController and displays the Account name for the ID passed to it.
1 2 3 4 | <apex:page standardController="Account" renderAs="pdf">
<h1>Congratulations!!</h1>
<p>You created a PDF for {!account.name}</p>
</apex:page> |
Test Class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | @isTest
private class Test_PdfEmailController {
static Account account;
static {
account = new Account();
account.Name = 'Test Account';
insert account;
}
static testMethod void testPdfEmailer() {
PageReference pref = Page.PdfEmailer;
pref.getParameters().put('id',account.id);
Test.setCurrentPage(pref);
PdfEmailController con = new PdfEmailController();
Test.startTest();
System.assertEquals(2,con.accounts.size());
// populate the field with values
con.accountId = account.id;
con.email = 'test@noemail.com';
// submit the record
pref = con.sendPdf();
Test.stopTest();
}
} |
Categories: Apex, Code Sample, Salesforce, Visualforce














[...] my last post, Create and Email a PDF with Salesforce.com, I received a few comments whether it was possible to do the same with Document stored in [...]
Very nice. Anyother Sample codes??
I am looking to mail merge a document, covert to PDF and email, when an opportunity stage changes. Is this possible.
Hi Jeff, thanks for all the great posts. I’ve really been able to learn a lot from your examples!
My pleasure @Pat!!
Hi,
I’m trying to email an document that has been loaded into the Content section for a particular account.
Hi,
i am trying to get the records of salesforce into a CSV file using scheduled apex.
if anyone has sample code of that kind will be of great help for me..
Hi, that is really cool. I have been trying to create a form from a visualforce page and then send it.
Hi, that is really cool. I have been trying to create a form from a visualforce page and then send it.
Hi Jeff, Great work! this will be very helpful, i wanted to know if it was possible to do this all from one button on the account.
We have the rep’s email on the account page so it would be cool if there was an email PDF button that generated the dynamic PDF based on the current account ID and emailed it to the email field on the account.
could you point me in the right direction?
Thanks
Dave
@Dave, that should be totally possible. You’d need to create a new button on the Account layout that basically calls this same visualforce page with some minor tweaks. So your button would pass over the account id (instead of the user choosing it from the select list) and then you’d have to figure out which email you want to use and query for it or pass it over with the button. The Visualforce page would load, use the account id to get the right data, create the pdf and then mail it. The resulting visualforce page would probably just show some success/failure message. HTH!
Hi Jeff,
Thanks Jeff for great article.It is really helpful to all SFDC developers.
I am having bit deterrent requirement , where they want to attach an pdf file which is available as a public url (Hosted on some site other than Salesforce). I used same code but my PageReference points to URL of external PDF file,. When I run this code it does not throw error but the page keeps loading without any errors. Can you guide me how to attach external PDF files instead of other visualforce pages with renderAs=’pdf’
Hi, Thanks a lot for the series of articles you are writting for Apex and Visualforce. This is helping a lot for all SFDC developers.
I this article you have shown how to attach Visualforce as a PDF attachment tp Apex email. Can you suggest how we can do same thing if the attachment in not a VF page but a file which is hosted on some other domain but with public access.
I have tried some ways to do this including HTTP callouts to file url and using getContentAsPDF method of page reference with no luck
Please refer following for details:
http://boards.developerforce.com/t5/Apex-Code-Development/How-to-attach-external-PDF-file-to-the-email-sent-via-Apex-code/m-p/242951
@Rohit, you might want to look at making the files available on a Force.com site.
Your info is always greatly appreciated. I need to use a template to generate the body for the PDF. Is this possible?
Thanks..
@Elly, can you explain what you mean by “template”? Is this a Visualforce template, an email template, etc?
Just saw your question. I actually got it all working using a VF page. So now we are changing the email templates we used to send to VF pages.
I create the pdf from the VF page and attach it to the document. Works great thanks to you!
But now my Test is failing with this error:
Methods defined as TestMethod do not support getContent call, test skipped
How do I get around that?????
Elly, no way around the issue with testing as of right now. Vote for this Idea: http://success.salesforce.com/ideaView?c=09a30000000D9xt&id=08730000000HzknAAC
So I can’t deploy my code? ARGH!!!
OK I set one of my passed parameters to Testing and in the controller I check if it is != ‘Testing then I getContent otherwise I skip that part. It covers enough to pass….. Isn’t this fun??
I voted for the idea….
In your post you have:
mail.setHtmlBody(‘Here is the email you requested! Check the attachment!’);
I am doing this also, but I need to have default text in the Body and allow the user to update. When I send, it uses my original Body and not the changed. If I don’t want the deault text, I use
public String Body{get;set;}
and it works beautifully. But if I do the following it doesn’t:
public string Body {
get {
Body = ‘This is the text Change whatever…..’;
return Body;
}
set;
}
I have tried various thing with the set but nothing works. Any ideas? Thanks so much for your help!
Hi Jeff,
Great post!!!
My requirement is to send Email from a list view with attachment as pdf from record detail and emailId as record email . I just tweaked your code and made it work. It seemed to work fine for 20 records( attachment size is around 50 KB) . But when it was more than that time out error happened. I tried by making it run in a batch and future calls. both sent empty pdfs.
Is there any work around
Hi, Is this possible through trigger also..?
Hi Jeff,
I am looking for something what pinky has asked.. can you please reply to that?
Hi Jeff, Can you please help me
I want to create a send email button which capture the a page from an object – “click 10 point”. When a opportuntiy is created, in the opportunity page there is a option for 10 point and when the user clicks it takes some of the field from opportunity into this click 10 point and a different page is displayed with some new fields. Now, I want to capture and send an email for this page using on send button. How to do create that send button? I am new to visualforce page and all..
Thanks,
Abhishek
Hello I have a VF page , which takes the value as Input , after clicking on save button the record should save as well as PDF should generte with values which In insterted
1. I have a VF page
2.I wrote one extension class
3.I wrote one more VF which generates PDF
————————————————————————————————–
extension class—
public class MyController1 {
private final Customer_order__c o;
public MyController1(ApexPages.StandardController stdController) {
this.o = (Customer_order__c)stdController.getRecord();
}
public PageReference save()
{
//logic to save your data
ID theId = ApexPages.currentPage().getParameters().get(‘id’);
//ID theId = ApexPages.currentPage().getParameters().get(‘id’);
if (theId == null)
{ // Display the Visualforce page’s content if no Id is passed over
}
// Redirect the user back to the original page
PageReference pageRef = new PageReference(‘https://c.na12.visual.force.com/apex/blogspotpdf’+ theId);
pageRef.setRedirect(true);
return pageRef;
PageReference p = new PageReference(‘https://c.na12.visual.force.com/apex/blogspotpdf?id=!name’);
p.setRedirect(true);
return p;
//This assumes that your thank you page is also a custom VF page. If not, then you can do something like PageReference p = new PageReference(‘your Thank you page URL’);
p.setRedirect(true);
return p;
}
}
——————————————————————————————
VF to generate PDF
Hello {!$User.FirstName}
Custom Order Details
Name:{!Customer_order__c.Name__c}
Email_Address : {!Customer_order__c.Email_Address__c}
Mobile : {!Customer_order__c.Mobile__c}
Residencetype : {!Customer_order__c.Residencetype__c}
City/Town : {!Customer_order__c.City_Town__c}
State : {!Customer_order__c.State__c}
Total price : {!Customer_order__c.Total_Calculated_price__c}
ZipCode : {!Customer_order__c.ZipCode__c}
<!–
Name : {!Customer_order__c.Name__c}
Email_Address : {!Customer_order__c.Email_Address__c}
Mobile : {!Customer_order__c.Mobile__c}
City/Town : {!Customer_order__c.City_Town__c}
State : {!Customer_order__c.State__c}
Residencetype : {!Customer_order__c.Residencetype__c}
Total price : {!Customer_order__c.Total_Calculated_price__c}
ZipCode : {!Customer_order__c.ZipCode__c}
<!–
–>
——————————————————————————————————————————————–
But when after inserting the records I click on save button …..”Id” contains null
acoording to me id should contain value
one more thing
overriding of save button automatically save the record or do I need to insert the record
——————————————————————————————————————————–
I have to generate the PDF , please suggest me