Newer Version Available
Using Custom Controllers within Visualforce Email Templates
Visualforce email templates can leverage custom controllers to render highly customized content. To do so, include a custom component in a Visualforce email template that uses that custom controller.
1public class findSmithAccounts {
2 private final List<Account> accounts;
3
4 public findSmithAccounts() {
5 accounts = [select Name from Account where Name LIKE 'Smith_%'];
6 }
7
8 public List<Account> getSmithAccounts() {
9 return accounts;
10 }
11}1<apex:component controller="findSmithAccounts" access="global">
2 <apex:dataTable value="{!SmithAccounts}" var="s_account">
3 <apex:column>
4 <apex:facet name="header">Account Name</apex:facet>
5 {!s_account.Name}
6 </apex:column>
7 </apex:dataTable>
8</apex:component>1<messaging:emailTemplate subject="Embedding Apex Code" recipientType="Contact" relatedToType="Opportunity">
2 <messaging:htmlEmailBody>
3 <p>As you requested, here's a list of all our Smith accounts:</p>
4 <c:smithAccounts/>
5 <p>Hope this helps with the {!relatedToType}.</p>
6 </messaging:htmlEmailBody>
7</messaging:emailTemplate>Notice that although the relatedToType attribute is required by the emailTemplate component, it does not have any effect on this example. It has the value of "Opportunity" only to show that it can take an object value that is different than the object used in the custom component.
Debug logs don’t contain information, such as System.debug() messages, from component controllers used in Visualforce email templates. This limitation occurs because of the order of execution on the Salesforce Platform. Debug logs are written when Data Manipulation Language (DML) actions are committed to the database, but emails are sent after DML actions are committed to the database. In other words, writing debug logs is on-commit logic, but sending emails is post-commit logic. Therefore, if invoked from a Visualforce email template, custom components and their controllers don’t run until after the debug log is already generated, so they don’t appear in the debug log. As a workaround, use a try-catch block to catch errors in the custom component rendering process.