[SalesForce] Pass List of sObject to VF email template / Best way to get just inserted records

Looking for assistance to my approach here. What I'm trying to do is set up a notification such that when a user clicks a button to insert records, it will include data from the newly inserted records to be sent out. The notification needs to be dynamic in that it should only include a subset of the records based on the target recipient. I've set up a VF email template with a VF component and controller in order to dynamically select the records for the notification, but the problem I'm facing is that there could be pre-existing records that would get included in the query and subsequently the notification. Now I would think there would be two ways to go about handling this, I just don't know how or if they're even possible.

  1. Pass the list of records being inserted to the VF template. Is there a way to "inject" data into a VF template? To my understanding, the component/controller on the VF template can only retrieve data.

  2. Retrieve only the "just inserted" records in the VF component controller. What would be the best approach for doing this? Add a filter criteria to my query like CreatedDate >= System.NOW()-<1 min>? [pardon the lack of correct syntax.] I imagine this wouldn't be best practice and could have potential to incorrectly include records if multiple users are clicking the button and inserting records at the same time. Is there a way to know if records are "fresh" to the database? The method that is called to send the email message is executed at the time the user clicks the button and the records are inserted, so the record insertion and email message generation would be in the same execution context, is there some way to utilize that fact?

I realize I could also hard-code the HTML email into my original controller which would give me access to the just-inserted records, but I imagine that would go against the MVC framework, as well as I'd have to re-deploy the code every time I needed to edit the email notification.

I'm definitely open to suggestions for an alternative approach, or am I just SOL here?

Thanks!

Best Answer

Your correct you cannot pass request state into the email generation process when using an Email Template and option 2 is tenuous as you say. What you can do is pass database state into the template, via the setWhatId method... Here is something to consider...

1. Setting up your Database State

In your case you could create two custom objects NotificationEmail and NotificaitonEmailItem in a master detail relationship. Also ensure that you have lookup fields on these objects to point to the specific records your interested in. This will be important within your email template.

2. Passing in your Database State to the Email Template

Prior to sending the email insert records into these objects to reflect which items you want to include then pass the NotificationEmail record Id in as the setWhatId. The email template can then access this record via the 'relatedTo' variable and its children (NotificationEmailItem) via standard Visualforce expressions. You can also pass in this record to your component by passing the relatedTo, hence it can dynamically query NotificationEmailItems if you want to do something specific. Though you may find at this stage regular Visualforce has sufficed (by binding to relatedTo.NotificationEmailItems__r for example), such that you don't need your component.

3. Cleaning up your Database State

You may be able to clean your state records up after issuing the sendEmail call in the same request, I suspect so, as from what I've experienced its not asynchronous. However if run into problems cleaning up immediately after yourself, you can always do so the next time round by simply querying for records by CreatedByUser on the NotificationEmail object and deleting them.