The following post explains how to send a complex, stylized table formatted email with data records from your Salesforce system. For this, we will be using Visualforce Email Template, Visualforce Component with an apex custom controller.
The visualforce component will be placed in the email template; the custom controller will pull the required data from Salesforce using SOQL query and displays it in the Email Template.
First create the email template (of type Visualforce) by clicking New Template in Communication Templates in Salesforce
Here’s the email template (of type Visualforce). Observe that the email body contains the VF component along with the text content.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<messaging:emailTemplate subject="Opportunities to verify" recipientType="Contact" relatedToType="Account"> | |
<messaging:htmlEmailBody > | |
Good Morning! Here are the opporunities that needs verification. <br/><br/> | |
<c:OpportunitiesToVerify accountIdValue="{!relatedTo.Id}" /> | |
ref: {!relatedTo.id} | |
</messaging:htmlEmailBody> | |
</messaging:emailTemplate> |
Note: We are passing the accountId from the email template to the visualforce component as an attribute. This accountId will be used in querying the related Opportunity records to display in the email.
Here’s the code for the VF component. The component has to display Opportunities and another repeat to show the related Matches as well for each Opportunity. (Match is an object that is a related list to opportunities). Of course, you can add all the kind of styling you want in the component as it is pure html data table.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<apex:component access="global" controller="OppsWithMatches"> | |
<apex:attribute name="accountIdValue" type="String" description="This is the Id of the account" assignTo="{!accountId}" access="global" /> | |
<table class="table"> | |
<thead> | |
<tr> | |
<th>Opportunity Name</th> | |
<th>Opportunity Description</th> | |
<th>Opportunity Amount</th> | |
</tr> | |
</thead> | |
<tbody> | |
<apex:repeat value="{!Opps}" var="pos"> | |
<apex:repeat value="{!pos.Matches__r}" var="match"> | |
<tr> | |
<td>{!pos.Name}</td> | |
<td>{!match.Name}</td> | |
<td>{!match.Email__c}</td> | |
</tr> | |
</apex:repeat> | |
</apex:repeat> | |
</tbody> | |
</table> | |
</apex:component> |
And finally here is the apex class where we query the Opportunity and related matches (in confirmed status)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
global with sharing class OppsWithMatches{ | |
global List<Opportunity> Opps{get;set;} | |
global String accountId{get;set;} | |
global account account{ | |
get { | |
Account = [Select Id, name from Account where id =: accountId]; | |
return account; } | |
set; | |
} | |
global OppsWithMatches(){ | |
} | |
global List<Opportunity> Opps{ | |
get{ | |
posToDisplay = new List<Opportunity>(); | |
List<Opportunity> oppList = [SELECT Id,Name,Description,Amount,(SELECT Id,Name,Email__c FROM Matches__r) FROM Opportunity WHERE AccountId=:accountId]; | |
for(Opportunity p:oppList){ | |
Boolean display = false; | |
for(Match__c m:p.matches__r){ | |
if(m.status__c == 'Confirmed'){ | |
display = true; | |
} | |
} | |
if(display==true){ | |
posToDisplay.add(p); | |
} | |
} | |
return posToDisplay; | |
} | |
set; | |
} | |
global String NewLine { | |
get { return '\r\n'; } | |
set; | |
} | |
} |
Here’s the complete github code.
You might also be interested in reading building dynamic Search functionality in Visualforce page with pagination.
Hi thanks for this article!
Im trying to get this Email Template in a standart email action in one of my Objects. Until there everything is working fine. But do you know if there is a way to edit this template in an email action? I get an error: This email template content can’t be modified.
thanks!
LikeLike
You have to go to the template first and edit there. Once the template is updated, come back to the email > properties. You’ll see the option to update the email with the latest changes from the template.
Hope that’s clear.
LikeLike
Hi,
I have almost same implementation to display standard and custom object records in Visualforce Email Template.
relatedToType is Account.
Standard object = AccountHistory
Custom object = custom history
It is working fine when there are records in AccountHistory i.e. records are getting displayed in email.
But it is failing when there are records in Custom History only, and not in AccountHistory, in this case email is coming as blank.
Not sure why it is behaving like so.
Thanks in advance
LikeLike
Im getting HTML tags in the email when I used above code.
LikeLike
LikeLike
You can try this
LikeLike
Absolut fantastic, you made my day!! Before I found your side I was trying everything to pass those attributes from the VF component to the controller but nothing seems to work. I used assignTo with getParameter() etc. etc. but always got a NULL for the
Then I found your solution and what could I say WOW…. I only had to change the variables and controller from Public to Global and it works.
In every possible solution I found so far in the net, they use Public nd it didn’t work.
Thanks a lot man!!!
LikeLiked by 1 person
Ah, great to hear that. Thanks
LikeLike
Please find my code which is not triggering email.
Apex class:
public class acctTemplt
{
public Id Traveling_Dependents{get;set;}
public List getopptys()
{
List oppty;
oppty = [SELECT Dependent__c FROM Traveling_Dependents__c WHERE Travel_Request__c =: Traveling_Dependents];
return oppty;
}
}
VF Controller:
Dependent Name
{!o.Dependent__c}
Email Template:
Hi,
Below is the list of Travelling Dependents for your Travel Request {!relatedTo.Name}.
Regards,
Kaativik
LikeLike
Hi sfdcFanBoy, I was working on same scenario but different objects.
Travel_Request__c
Travel_Dependents__c
These two objects are connected with masterdetail relationship with field name “Travel_Request__c”, when I replace Accountid with Travel_Request__c in
global String accountId{get;set;}
then I am getting error, can you please help me out for this
LikeLike
could you please provide me githud code bcz when i go click on link its not working.
LikeLiked by 1 person
Oh. Can you try this and see if this works for you?
https://github.com/sfdcfanboy/VFEmailTemplateWithController
LikeLike
spelling mistake in line no 18 : Opportunity
LikeLiked by 1 person
oops! corrected. Thanks for the catch.
LikeLike