VisualForce Email Templates
When I saw that Winter ‘09 was going to include VisualForce email templates, I got really excited. I thought about all the cool things I could do with pages running custom controllers and getting whatever data I wanted.
And then I saw that VF email templates weren’t going to be able to use custom controllers and I wrote them off.
Well, I’ve dug back into them and turns out they are going to be amazingly useful. And when we get custom controllers on them, they will be seriously butt-kicking.
Here’s a VF email template:
<messaging:emailTemplate subject="Thank you for your Support!" recipientType="Contact" >
<messaging:htmlEmailBody >
<html>
<body>
<p>Hello {!recipient.Household_Greeting__c}--</p>
<p>Thank you so much for you giving this year. Every gift helps us make a difference in our envrionment...</p>
<apex:outputPanel rendered="{!recipient.Total_Gifts_YTD__c>0}">
<apex:outputText rendered="{!recipient.Total_Gifts_YTD__c>0}">
<table>
<tr>
<td>Gift Date</td>
<td>Check Number</td>
<td>Check Date</td>
<td>Amount</td>
</tr>
</apex:outputText>
<apex:repeat value="{!recipient.OpportunityContactRoles}" var="opps" id="theRepeat">
<apex:outputText rendered="{!opps.Role=='Individual Donor'&&opps.Opportunity.IsWon&&opps.Opportunity.Year__c=='2008'}">
<tr>
</apex:outputText>
<apex:outputText rendered="{!opps.Role=='Individual Donor'&&opps.Opportunity.IsWon&&opps.Opportunity.Year__c=='2008'}">
<td><apex:outputField value="{!opps.Opportunity.CloseDate}"/></td>
<td><apex:outputField value="{!opps.Opportunity.Check_Number__c}"/></td>
<td><apex:outputField value="{!opps.Opportunity.Check_Date__c}"/></td>
<td><apex:outputField value="{!opps.Opportunity.Amount}"/></td>
</apex:outputText>
<apex:outputText rendered="{!opps.Role=='Individual Donor'&&opps.Opportunity.IsWon&&opps.Opportunity.Year__c=='2008'}">
</tr>
</apex:outputText>
</apex:repeat>
<apex:outputText rendered="{!recipient.Total_Gifts_YTD__c>0}">
</table>
</apex:outputText>
</apex:outputPanel>
</br></br>
We look forward to seeing you in 2009!
Best,
Steve
</body>
</html>
</messaging:htmlEmailBody>
</messaging:emailTemplate>
In line 1 I connect this template to the Contact record as RecipientType. Then when I send to a Contact, I can merge fields. So in line 5 I’m pulling a custom field on Contact called Household_Greeting__c. So far so good.
On line 7 I start building an HTML table, and I only want to show it if this Contact has given money this year, so I render only if their Total_Gifts_YTD__c>0. Slick. No custom controller, but I can still put some logic in there.
On line 17 I create a repeat that will loop through all OpportunityContactRoles this Contact has. Whoa! I suddenly have access to all their donations!
On 18 I want to create a table row, but only when the opp we’re dealing with is won, was in this year, and this contact was the individual donor role on it. We have to repeat the same rendering logic on each field as well.
I’m looping through OpportunityContactRoles, but I want Opportunity information. That’s really easy. On line 22 I get {!opps.Opportunity.CloseDate}–the close date off the Opportunity on this contact role. Simple!
So with no controller, I can get any related list off the Contact and iterate through it. And I can traverse across multiple relationships. Only getting the records I care about requires some rendering hacks, but it works. Also, I don’t think I can sort the items at all.
I’m impressed with what VisualForce email templates can do with no controller. Check them out, they’re easy to use! And when they give us the ability to use Custom Controllers, we’ll be able to do crazy things.
Update: In the comments Andrew sets me straight on a key feature–you can put custom VisualForce components in VisualForce email templates. Wow. We can now do just about anything we want. Seriously, there are very few limitations to what can be done now. Thanks Andrew for pointing out that killer feature!

November 14th, 2008 at 8:13 am
Steve,
This is super! I’ve been trying to use a third-party application to generate invoices, listing events only if the Billable_Hours__c checkbox is checked. Surprisingly difficult to do. It would be so much easier if I could just generate an email template and send a simple email to each client once a month. I’ll take your code as a starting point, and will try to list all Events on the Opportunity, sending the email to the Primary Contact. Hopefully it will work.
Super starting-point! Always a pleasure to build upon your great examples.
David
November 14th, 2008 at 8:17 am
You might be interested to know that you can include custom components in Visualforce Email Templates and those components can have apex controllers on them. Feelin’ crazy now?
November 14th, 2008 at 8:57 am
Rockin’
April 1st, 2009 at 7:05 am
Is access to opportunity line items from such visualforce templates also possible?