function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
teknicsandteknicsand 

Email with pdf attachment

I'm looking to implement a VF email that will attach a pdf file generated dynamically from vf page. There is an app installed in the environment, which pulls data from an external source, and displays it using S-control, and also has an option of displaying the same information as a pdf(dynamically generated) using visualforce. I need to send this information, or the pdf file, as an email attachment to customers. I've gone through chapter 13 in the force.com cookbook and the Visualforce Email2pdf article. I'm a little confused as to how to approach this. If someone can point me in the right direction, I would appreciate it.

 

Thanks,

 

Cheers,

 

Sand

BrianWKBrianWK

Teknicsand,

 

I'm actually doing the same thing. I'm using the singleEmailMessage method. My Visualforce page dynamically generates a Purchase Agreement off of an Opportunity. Here's the relevant portions of the method that's creating the attachment:

 

// Retrieve the PDF as a Blob from the Visualforce page ID OpportunityId = this.controller.getRecord().id; PageReference SalesPAPDF = Page.SalesPAPDF; SalesPAPDF.getParameters().put('id', OpportunityId); Blob pdf = SalesPAPDF.getContent(); //set Email Attachment Messaging.EmailFileAttachment mailAttachment; mailAttachment = new Messaging.EmailFileAttachment(); mailAttachment.setFileName('PharmacyOneSourcePurchaseAgreement.pdf'); mailAttachment.setBody(pdf); mail.setFileAttachments(new Messaging.EmailFileAttachment[] { mailAttachment });

 

 

The rest of the method is a slightly altered version of the SendEmail example provided in the book. Hope this helps!

teknicsandteknicsand
I've written an Apex Class to send out an email using the singleEmailMessage method. I have a sample VF page created which renders as a pdf. Now is there a way to use the url of the VF page as a source for creating the attachment for my email, in the Apex class?
BrianWKBrianWK

PageReference SalesPAPDF = Page.SalesPAPDF; SalesPAPDF.getParameters().put('id', OpportunityId); Blob pdf = SalesPAPDF.getContent();

 

That's what this portion of code does. You're really creating a page reference and not directly using the URL - but you add a Parameter into the "URL" which is the ID of the Object the page needs. In my casethe Opportunity ID. The first to lines are pretty much the same as saying - I don't care what page you're own now, but here's a url to /apex/SalesPAPdf and I want ?id=OpportunityID (the actual number of course) appended.

 

At that point you use Blob pdf to create a new blob variable that has the content of the VF page reference you created above.

 

If you have a separate email class, you'll need to pass the information into the class. I'm not sure what the best practice is - to pass the VF Page name and ID and create the page reference and blob pdf in the Email class or to just pass the blob.

 

If it was me I would try to pass the blob first - but I can't really direct you on how to do that since I don't have an example code for it yet.

teknicsandteknicsand

Thanks Brian for your help. Appreciate it. I managed to get the mail to be sent out with another VF page as its pdf attachment. How do you trigger your mail to be sent out? I tried triggers, but I got an error saying visualforce wont allow you to send data using triggers or something of that sort. Now I'm trying to have a custom button, to fire off the email, but after selecting detail page buttons > VisualForce page as the options, I'm not seeing the VF page that initiates the whole process in the drop down options, I only see my dummy VF pdf file. Any clue?

 

Thanks,

 

Cheers,

 

Sand

Message Edited by teknicsand on 02-19-2009 02:21 PM
BrianWKBrianWK

Teknicsand,

 

The way I'm handling this is through a command button on the pageblock. The buttion calls my Validate Method in my controller extension. If all my validation go through it calls my SendEmail method (same class). And the SendEmail Method takes care of all my email, attachment, and activity needs and sends me back to the Opportunity that originated the whole process.

 

So you have two issues.

 

1. Command Button in Visualforce page

    This is really easy. You just set the apex : commandbutton to have an Action= to a method. This method is in your controlle and can be your email method.

 

2. Command Button in standard salesforce page

    If I understand it, only pages that share the controller show up in the drop down here. So you have two choices - you can either turn your page/controller into an extension - or you can make it generic. I don't remember the exact wording but there's some apexpage controller code that you can add to the top of your controller.

 

You might be able to get away with doing a Detail button with URL code. Something along the lines of '/apex/PageName?id=' + ObjectID (if needed. if you don't need the ID parameter leave it out.

 

Good luck!

 

are you doing your Send Email in a separate class/function? If so how and what are passing through? my next project is "cleaning" up the email code that I"m using in 3 different places so it's all referencing just 1 class.

teknicsandteknicsand

Brian,

 

My task got just a little more complicated now. I have to fit the 'sending out of the email with the attachment' into a workflow process that is already in place.I'm not sure how I'm going to tackle that. Have to give it a thought.

I did actually use the apex command option, but its in a VF page. I would need it, if I went this approach that is, in the standard page. So I'll check on those 2 options you mentioned if I end up taking the button approach.

I have my email function in the same class. But I will try separating it out once I'm done with the trigger and other customizations for this email. Will post here if I make any headway with that.

 

Thanks again!!

 

Sand

 

BrianWKBrianWK

Here's something to think about.

 

I think you can send e-mail via apex triggers but it has to be asynchronous so the trigger needs the @future added to the top.

 

 

So if you're doing this as part of a workflow (sf workflow) and you can't use an e-mail template (you could do a vf template and create a custom component) - you could always use the workflow to update a hidden check box field. Then the trigger fires when after update when checkbox= true, send email and unchecks the box.

 

Be interested to hear how things turn out. Good luck!

teknicsandteknicsand
I did create a separate class for the email, and I'm passing the blob, and a couple of other objects that I would need in the email. My specs changed again, and now I need to trigger this email based on a field update in the accounts object. When that particular field gets populated, the trigger needs to fire, which will call the VF page controller (if thats possible), and then the controller makes a call to the email class to send out the email.  I've kind of hit a wall with my thought process here. Any suggestions?
BrianWKBrianWK

teknicsand,

 

I'm by no way an expert - so don't take this as the gold lining truth. Here's what I'm thinking though.

 

1. Since your e-mail is in a separate class it should be no different than any other class - meaning it can be called by a VF controller or a trigger

2. The controller should be called only from the page providing the email

3. Your trigger is going to have to by asynchronous in order to send the email (not 100% on this)

4. Since triggers are done Before/After/ Inserts/Update/deletes you'll need to fire the trigger.

 

So here's what I'm thinking.

 

1. Controller - CreatePDf

2. Class - SendEmail

3. Trigger - SendAccountEmail

4. Workflow - Field Update Account

5. VF Page - PDF_Page

 

This should be done without the user having to provide immediate input to the controller or VF page. I've done something similiar but not with emails. I have a trigger/workflow that creates cases based on certain criteria

 

Process:

 

Workflow updates account field. I recommend 2 fields. 1 field  that you need updated, and 1 field to toggle the firing of the trigger.  Field: Account_YourField__c and Account_FireTrigger__c (checkbox). Workflow updates Account_YourField__c

 

Trigger: After Update/After Insert @Future - If Account_YourField__c is = "blah" and Account_FireTrigger__c = false then

PageReference VF_PDF_Page = Page.PDF_Page;   

Blob pdf = VF_PDF_Page.getContent();

 

SendEmail(pdf); // this calls the EmailClass and passes your pdf If your class doesn't hard code the To or CC addresses you'll need to pass that information.

 

Account_YourField__c = true; //this is set to prevent the trigger being fired again on future updates

 

 

the getcontent() should pull the content of your VF_PDF page - just make sure it's set to render as PDF. This should "fire" the controller being used on the VF_PDf hopefully the controller is just creating PDF since no other methods would be called unless called within a method being used by the VF_PDf Page

teknicsandteknicsand

Hi Brian,

 

I appreciate all your suggestions and helping me think through this. 

 

The problem here though, is

 

PageReference VF_PDF_Page = Page.PDF_Page;   

Blob pdf = VF_PDF_Page.getContent();

 

will not work in a trigger. So I need to find a way to call the method that is implementing this part, which is located in the controller associated with the initial vf page, from the trigger. But I can't seem to find a way to do it without going through the VF page and displaying the command link button to call the method in the trigger. I have it working that way via a custom link as suggested before, but its not an ideal solution for our situation.

 

Sand

 

BrianWKBrianWK

Can you call the controller method from the trigger?

 

There was an example here link.

 

the important part is the blob passing to the sendemail class. So I would think you would have a method in your controller that creates and returns the blob. In your trigger call that class and set the return to a blob variable that you pass to SendEmail.

 

The only other thing I can think of is having pass the parameter. If your PDF Page requires an ?id=SalesforceID in the URl you'll have to set that Parameter  wet getParameters().put('id', SalesforceID)

 

teknicsandteknicsand

I've posted my code here.

 

 

Blob variable is in the pagereference method, and it returns only system.pagereference. The example that you

linked, has the pagereference as a static method, but that doesn't work. So without the blob, I won't be able

to pass it as a parameter to my sendemail class.

 

I'm looking at the @future method though, my understanding of it is still not good, but hopefully it could resolve some part of the issue here.

 

 

Message Edited by teknicsand on 02-24-2009 01:28 PM
Message Edited by teknicsand on 02-24-2009 01:29 PM
teknicsandteknicsand

I resolved the error of not being able to make callouts from trigger using @future. But I receive a different error, and the debug logs look like this. Any experience dealing with such an error or know what this is about?

 

Thanks.