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 

trigger VF email based on a field update

Hi everyone,

 

I've been working on getting an quote sent out as a pdf to customer using visualforce. Here, for some context.

I nailed this down, but I'm unable to come up with a way for this email to be fired based on a field update in an object. I would like to have this whole process run in the background, i,e. no new window which prompts for user to click any button. I have created a custom link (last resort) to display on the opportunity page layout, which redirects to a visualforce page, where a send email button needs to be clicked to send the email out to that particular contact whose on the opportunity record. I would like to move this process to the background and have it run automatically when a particular field is updated.

 It would be great if I can write a trigger to run based on a field update, grab the context of the record in view (record id), and pass it to an apex class, where i can use it generate a link for pdf attachment using pagereference, and pass the parameters to my apex email class to send out the email.

Can this be done? If yes, any pointers, or else any alternatives.

 

Thanks

Deepak PansariDeepak Pansari

Hi,

 

In this case Triggerwould be the best option, you can write trigger on that object and wheneverfield is updated then trigger will fire. 

 

- Deepak 

teknicsandteknicsand

How do I pass the current page reference to the page controller or apex class from the trigger then, once it fires based on the field update.

 

KeithJKeithJ

Hi there.

What have you got so far? 

I can't see why you couldn't do this with a trigger. 

But there are some things you have to consider.

 

Your quote will have to be attached to the opportunity manually as you cannot use

the neat method getContent to get the content of your generated quote.

So the PageReference pr = Page.QuotePage;

ApexPages.currentPage().getParameters().put('Id', someId);

Messaging.EmailFileAttachment myFileAttach = new Messaging.EmailFileAttachment();

myFileAttach.setContent(pr.getContent()); approach won't work. you will have to query for it.

 

if you are using a trigger to automate the whole proccess i.e. if the stage of the opportunity changes

to a certain stage and an email is fired - who does the email get sent to? Are you conscious of which contacts

of the opportunity's account receive the quote?

 

Regards,

teknicsandteknicsand

I haven't made any progresson this so far, except for having a custom link, like i explained. Unfortunately, we need the auto generation of the pdf, which was the reason we went with Visualforce. So are you saying that pdf can still be generated dynamically by querying instead of using pagereference(which will not work as you said).

The email is actually going to be triggered off a custom field in accounts when the custom field gets populated after synch with an external source. And the email needs to go out to the contact person(customer) whose information will be retrieved from another custom field in opportunity. 

KeithJKeithJ

That sounds good. :) I have done this before - except not in the context of a trigger.

What I had was a custom button on opportunity detail page that links to an extremely simple vf page

that calls a method (When loaded - action attribute of apex page tag) in an apex class.

The Id of the opportunity is passed to this simple (proxy) vf page initially. Now, in the Apex method that is called,

it calls 

PageReference pdfQuotePage = Page.VFQuotePage; pdfQuotePage.getParameters().put('Id',contextOpportunity.Id); Blob pdfBlob = pdfQuotePage.getContent();

 What this does essentially, is pass in the Id of the opportunity to the page VFQuotePage. This page is the page that has the

renderAs="PDF" attribute and is responsible for actually generating the quote.

Later on, another method in my apex class, creates an attachment of type pdf and inserts it.

The key is setting the attachment body to be that of above...

 

Body=pdfBlob

 

So in your instance, i suppose you could have a trigger that fires when your custom account field is updated.

I don't see why the trigger could not call a method of an apex class that does the same as what I mentioned above.

You cant utilize the getContent() method in a trigger, but it shouldn't stop you from calling an apex method that does! ;)

Regards

 

 


 

 

 

KeithJKeithJ

If I were you, I would use the Trigger as a proxy that listens for when your account field is updated and then

utilizes Apex methods that you have written in other classes - sort of like a facade pattern.

Facade Pattern

 

Regards

teknicsandteknicsand

//VF page to initiate email process <apex:page controller="myOpportunityController" tabStyle="Opportunity"> <apex:form > <apex:commandButton value="sendemail" action="{!getSamplevfpdf}"/> </apex:form> </apex:page>

 

 

 

//page controller public class myOpportunityController { public Opportunity getOpportunity() { Opportunity oppt = [select id, name from Opportunity where id = :ApexPages.currentPage().getParameters().get('id')]; return oppt; } public PageReference getSamplevfpdf() { Opportunity opp1 = [select id, name from Opportunity where id = :ApexPages.currentPage().getParameters().get('id')]; PageReference samplevfpdf = Page.samplevfpdf; samplevfpdf.getParameters().put('id',opp1.id); Blob pdf1 = samplevfpdf.getContent(); sendPDFEmailClass.sendmyEmail(opp1, pdf1); return ApexPages.currentPage(); } }

 

 

//Email Class

public class sendPDFEmailClass { public static void sendmyEmail(Opportunity opp, Blob pdf1) { Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage(); String[] toAddresses = new String[] {'xxxxxxxxxxx@gmail.com'}; //get it from contacts // String[] ccAddresses = new String[] {'sds@sds.com'}; mail.setToAddresses(toAddresses); // mail.setCcAddresses(ccAddresses); mail.setReplyTo('user@salesforce.com');//sf user email add mail.setSenderDisplayName('xxxxxxx');//sf user name mail.setSubject('Test mail'); //get info from custom object mail.setBccSender(true); mail.setUseSignature(true); String oppname = opp.name; mail.setPlainTextBody('This is a test email'); mail.setHtmlBody('Your name <b>' + oppname + 'is: get from merge fields'); //Attachments Messaging.EmailFileAttachment mailAttachment; mailAttachment = new Messaging.EmailFileAttachment(); mailAttachment.setFileName('samplevfattachment.pdf'); mailAttachment.setBody(pdf1); mail.setFileAttachments(new Messaging.EmailFileAttachment[] { mailAttachment }); //mail.setFileAttachments(fileAttachments); //send the email Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail }); } }


Right now, as you see from the VF page, the command link is calling the getsamplevfpdf method. 

 

 

 

How would I call getsamplevfpdf pagereference method from the trigger?
BrianWKBrianWK

Hey tek!

 

You're close here.

 

public PageReference getSamplevfpdf() { Opportunity opp1 = [select id, name from Opportunity where id = :ApexPages.currentPage().getParameters().get('id')]; PageReference samplevfpdf = Page.samplevfpdf; samplevfpdf.getParameters().put('id',opp1.id); Blob pdf1 = samplevfpdf.getContent(); sendPDFEmailClass.sendmyEmail(opp1, pdf1); return ApexPages.currentPage(); }

 

 

Right now you're returning the page reference. What you want to be returned to the trigger though is the blob!

 

So instead of Public pagereference you want public blob getSamplePDf()

 

Then in your trigger you'll call the reference

 

Blob PDFtoPasstoEmailClass = getSamplePDF();

 

This should return the PDF as a blob to your trigger. Then you pass the blob into your sendemail class.

 

 

teknicsandteknicsand

I get the following error when trying to insert a new opportunity. 

 

System.NullPointerException: Attempt to de-reference a null object: Class.myOpportunityController.getOpportunity: line 6, column 17

 

 

trigger OpportunityVFEmail on Opportunity (after insert,after update) { myOpportunityController a = new myOpportunityController(); Opportunity opp1 = a.getOpportunity(); Blob pdf = myOpportunityController.getSamplevfpdf(); sendPDFEmailClass.sendmyEmail(pdf, con1); }

 From what I can read into the error, it seems like the current page parameters are not returning anything in the controller code, for the query to pull up the record based on the id. 

 

 

 

 

KeithJKeithJ

Hi mate.

The problem is that you aren't referencing any VF page when you are calling the getOpportunity method, so

your class isn't getting any id... 

 

Could you not try:

//page controller public class myOpportunityController { public Blob getSamplevfpdf(Opportunity currentOpportunity) { PageReference samplevfpdf = Page.samplevfpdf; samplevfpdf.getParameters().put('id',currentOpportunity.id); Blob pdf1 = samplevfpdf.getContent(); return pdf1 } }

 


 Where you query for the relevant opportunity in your trigger and pass this opportunity in as an argument to your getSamplevfPDF method?

This way the blob is returned to you and you can call your sendMyEmail method with the blob....

best regards

 

 

 

teknicsandteknicsand
Thanks Keith for all your suggestions. That is exactly what I'm trying to acheive, is to get the id of the current record in the trigger code and pass it to my APEX methods and class. Do you know how I could access that? How do I select the current record in the trigger while iterating through the various records?
KeithJKeithJ

 

 

for (Opportunity updatedTriggerOpp : Trigger.new) getSamplevfPDF(updatedTriggerOpp.id);

 

You could loop through all the records in Trigger.new (or Trigger.old) depending on what your trigger does in particular.

Regards

 

 

 

teknicsandteknicsand

Thanks Keith. Got that part working, but it's not letting me pass paramters from the trigger to my controller method.

 

Get this error

 

 

Error: Invalid Data. Review all error messages below to correct your data. Apex trigger OpportunityVFEmail caused an unexpected exception, contact your administrator: OpportunityVFEmail: execution of AfterUpdate caused by: System.VisualforceException: Getting content from within triggers is currently not supported.: Class.myOpportunityController.getSamplevfpdf: line 21, column 17

 

 

 

teknicsandteknicsand

Solved this particular error by using @future, but I get a future handle error with a null pointer exception. Have you encountered anything like this before? Or have any idea what this is about?

 

Thanks.

trevorcgibsontrevorcgibson
Hey there.  Did you ever solve this issue?  I've got the same requirements, and I have run into the same roadblock involving the nullpointerexception.  Any suggestions would be appreciated :)
teknicsandteknicsand

Hi,

 

If you look here you'll notice page reference methods cannot really be used in a trigger or future callout methods. So, instead I went ahead and implemented a button to send out the visualforce email without the use of a trigger, that way, it gives you more control on when the email is sent out.

trevorcgibsontrevorcgibson

Thanks for the response!  I think I'm going to build an Apex web service that is called from a Windows Server Scheduled Task.

 

Too bad it can't be called from the trigger...would be very useful.

 

Trevor