+ Start a Discussion
Denis BrownDenis Brown 

getContent() returns Blob PDF-body in console, but HTML page (rendered like PDF) in Email service code

Hi everybody!

First at all: Happy New Year to you and your family. I wish you all the best in new 2014 year.

And about my case:

I use 'MyPdfRenderingPage.getContent();' method to get Blob PDF-body, create PDF attachment and sent it by mail.

And a code (please see below) works great in  Console's Execute Anonimous Window. It creates a mail with PDF file attached which I can open later.

But if I insert the same piece of code in my Email service (it receives a mail, creates a record and returns new mail with PDF attachment), it doesn't work correctly. I receive the mail, but can't open PDF attachment.

So I checked what does that Blob return content? If to execute 'MyPdfRenderingPage.getContent();' method in Email service, it returns HTML file with JS script inside leads to MyPdfRenderingPage.

In both cases the code runs by the same user, i did check it as well.

I have no idea what is wrong here...

Thanks a lot for your help.

----------
And that code below
______

Messaging.reserveSingleEmailCapacity(5);

Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();

String[] toAddresses = new String[] {'my@mail.com'};

mail.setToAddresses(toAddresses);

mail.setReplyTo('my@mail.com');

mail.setSenderDisplayName('Support');

mail.setSubject('New Record Created : ' + newRecords[0].id);

mail.setBccSender(true);

mail.setUseSignature(false);

mail.setPlainTextBody('Your new record has been created.');

mail.setHtmlBody('Your new record has been created.');


    PageReference pdf = Page.MyPDFpage;
    pdf.getParameters().put('id', (String)newRecords[0].id);
    pdf.getParameters().put('position', '1');
    pdf.setRedirect(true);

    Blob pageContent = pdf.getContent();

    Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment();
    efa.setFileName('PrintThisPDF.pdf');
    efa.setBody(pageContent);                                                          

mail.setFileAttachments(new Messaging.EmailFileAttachment[] {efa});                                                         
                                                          
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
sfdcfoxsfdcfox
If you're using the mass email API, or if the file exceeds 3MB once rendered, it will be linked as an attachment. It should be downloadable without logging in though; you may need to check your browser settings, because the default settings for any browser will allow the download.
Denis BrownDenis Brown
Dear sfdcfox! I appreciate greatly your answer! Happy New Year for you and your family!

I need to clearify the situation: when I execute a code (above) in Console, everything is just right. The system sends to my mailbox a message with attached PDF-doc, created from VF page. I can save and/or open it!
A problem occurs if I try to do the same thing with Email service.

I asked the same question at Stackexchange and got an interesting answer:

"You can't get the PDF content unfortunately.

While Email Services do run under a 'Context User', you will notice that UserInfo.getSessionId() returns null from any InboundEmailHandler implementation you may have.

The HTML with JavaScript is serving up a client-side redirect to a Salesforce login page. This is because pdf.getContent() runs in a different execution context that also lacks a Session ID at the time of making the request to render the page.

Salesforce have documented this:

    This method can't be used in [...] Apex email services"

(Thanks to user320)

And now I am thinking what to do.

- Can we SAVE that PDF rendered page like a PDF-Attachment or PDF-Document in our Org and than attach it to the mail? Can we do it in Email service execution context?

- Is it possible to run APEX code within any Session programmatically, in other words without a real person login in the system?

Thank you for help.
harsha__charsha__c
Can we have all the code that takes the PDF content of the vf page in a different apex class, instead having it in the Inbound Email Service and if we just make a call to that method and get it returned from there?

Something like this:

***************************************************************************************************

Messaging.reserveSingleEmailCapacity(5);

Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();

String[] toAddresses = new String[] {'my@mail.com'};

mail.setToAddresses(toAddresses);

mail.setReplyTo('my@mail.com');

mail.setSenderDisplayName('Support');

mail.setSubject('New Record Created : ' + newRecords[0].id);

mail.setBccSender(true);

mail.setUseSignature(false);

mail.setPlainTextBody('Your new record has been created.');

mail.setHtmlBody('Your new record has been created.');


    PageReference pdf = Page.MyPDFpage;
    pdf.getParameters().put('id', (String)newRecords[0].id);
    pdf.getParameters().put('position', '1');
    pdf.setRedirect(true);

    Blob pageContent = pdf.getContent();

    Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment();
    efa.setFileName('PrintThisPDF.pdf');
    efa.setBody(getPageContent((String)newRecords[0].id));                                                         

mail.setFileAttachments(new Messaging.EmailFileAttachment[] {efa});                                                        
                                                         
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });


+++++++++++++++++++++++++++++++++++++++++
public class PDFContentGenerator{
       public Blob getPageContent(String recordId){
               PageReference pdf = Page.MyPDFpage;
               pdf.getParameters().put('id', recordId);
               pdf.getParameters().put('position', '1');
               pdf.setRedirect(true);

               Blob pageContent = pdf.getContent();       
               return pageContent;
       }
}
+++++++++++++++++++++++++++++++++++++++++

******************************************************************************************************

Regards,
- Harsha
Denis BrownDenis Brown
Dear Harsha!
Thanks a lot for your great idea.

It was my first idea how to overcome this problem as well :)

But than I thought about this: it is going to be the same execution context for Handler and for all pieces of code which the handler calls. So there is still no Session ID... What is my worry.

But on Stack Exchange I got an idea to use Workflow rules sending Email Template... not sure if it works for my case (code should create PDF with different content on the fly)... but hope so much...
harsha__charsha__c
Hi Denis,

I am not sure about the context in which runs. Need to confirm it by implementing once.

If the content can not be generated in either email service OR any other in the same context, then only hope I believe is the Visualforce Email Template. 

Below are the steps I thought of

1. Create a visualforce temaplate by taking your SobjectType(The Sobject, whose id you are passing to the VF Page to get PDF content) as RelatedToType

2. Change the current vf page to a vsualforce component, which accepts 2 attributes (Id and position) and generates the PDF

3. Now design your visualforce temaplate for the PDF attachment as below

**********************************************************************************************************************
<messaging:emailTemplate subject="hello" recipientType="Contact" relatedToType="sObjectType(your object type comes here)">
<messaging:htmlEmailBody >
   *********your content of body
</messaging:htmlEmailBody>
<messaging:plainTextEmailBody >
    ---------- your content of body
</messaging:plainTextEmailBody>

<!--
<messaging:attachment filename="myContent.pdf" renderAs="pdf">
<c:myComponentToGeneratePDF position="1" id="{!relatedTo.Id}"/>
</messaging:attachment>
-->
</messaging:emailTemplate>
**********************************************************************************************************************

Accordingly, you have to frame the email(for example, setting templateId, relatedToId, etc)

Let me know if it blocks you anywhere....Happy if that helps  :)

Regards,
- Harsha




 
Denis BrownDenis Brown
Hi Harsha,

this idea looks great. Thanks a lot.

I am going to try it a little bit later - it is busy here now. I will let you know with results. Thanks again.

Regards,

Denis