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 component’s renderAs attribute. However, this method always seems to throw an error in the test class. See the PageReference documentation for more info. The method then constructs the SimpleEmailMessage object and then sends it on its way to the recipient’s inbox.

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

Leave a comment

Comments Feed26 Comments

  1. Create and Email a Document with Salesforce.com | Jeff Douglas - Technology, Coding and Bears... OH MY!

    [...] 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 [...]

  2. Hasan

    Very nice. Anyother Sample codes??

  3. Kim Cancel

    I am looking to mail merge a document, covert to PDF and email, when an opportunity stage changes. Is this possible.

  4. Pat M

    Hi Jeff, thanks for all the great posts. I’ve really been able to learn a lot from your examples!

  5. Jeff Douglas

    My pleasure @Pat!!

  6. John

    Hi,

    I’m trying to email an document that has been loaded into the Content section for a particular account.

  7. Pinky

    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..

  8. pepsiman

    Hi, that is really cool. I have been trying to create a form from a visualforce page and then send it.

  9. service à domicile

    Hi, that is really cool. I have been trying to create a form from a visualforce page and then send it.

  10. Dave

    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

  11. Jeff Douglas

    @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!

  12. Rohit Marathe

    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’

  13. Rohit Marathe

    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

  14. Jeff Douglas

    @Rohit, you might want to look at making the files available on a Force.com site.

  15. Elly Bockley

    Your info is always greatly appreciated. I need to use a template to generate the body for the PDF. Is this possible?

    Thanks..

  16. Jeff Douglas

    @Elly, can you explain what you mean by “template”? Is this a Visualforce template, an email template, etc?

  17. Elly Bockley

    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?????

  18. Jeff Douglas

    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

  19. Elly Bockley

    So I can’t deploy my code? ARGH!!!

  20. Elly Bockley

    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….

  21. Elly Bockley

    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!

  22. Partha

    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

  23. samish

    Hi, Is this possible through trigger also..?

  24. Krishna

    Hi Jeff,

    I am looking for something what pinky has asked.. can you please reply to that?

  25. Abhishek Ray

    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

  26. mayank

    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

Leave a comment

Feed

http://blog.jeffdouglas.com / Create and Email a PDF with Salesforce.com

WordPress Appliance - Powered by TurnKey Linux