Send Rich Email (Send HTML Email Action)
Note: There’s a version of this action that uses a Custom Property Editor to provide a more usable configuration experience. It requires a Spring ’20 Org that has been activated for the Custom Property Editor Pilot. Learn more here.
Installation (See bottom of page)
Flow provides a built-in Send Email action but it’s something of an underachiever. The sendHTMLEmail action uses the power of Apex and Flow Actions, easily installed and used from within Flow Builder. MVP Jeremiah Dohn pioneered this space several years back with his well received HTML Email Flow action. The version here is similar and adds a several of additional capabilities.
This improved email flow action supports:
- Rich, HTML email bodies that can use all of the capabilities of Flow’s Text Templates, including Bold, Italics, Underline, Bullets and Numbers, Left/Center/Right justification, URLs, images, fonts, and text size
- Email Templates (both Classic and Lightning) with field merge and letterheads
- Any combination of the following, for To, CC, and BCC
- A single email address
- A string collection of email addresses
- A collection of Contacts
- A collection of Users
- A collection of Leads
- Organization-Wide Email Addresses
- Attachments
- Ability to toggle on/off the use of the Salesforce per-user email signature
- Ability to provide a plain text body, an html body, or both
- Ability to set the ReplyTo email address and the Sender Display Name
- Multi-Language Support for Lightning Email Templates
Each email requires several components, but they may be constructed in many ways using the component parameters. The package includes a flow that produces emails in several scenarios. See Examples below.
Currently unsupported features include:
- Support for the MassEmailMessage API, enabling higher volumes
- Character Set setting
NOTE: Scratch orgs have a strict cutoff after sending just 50 email messages
If you’re interested in extending this class, please do so!
Index
There are many configurable options for this Action Component. Decide what and how your email needs to communicate, then choose the best combination to provide the needed communication.
Addresses (To, CC, BCC)
You can generate addresses from any of the following sources:
- A single email address
- A string collection of email addresses
- A collection of Contacts
- A collection of Users
- A collection of Leads
Example: Create a collection variable of strings and add individual email addresses to it:


// for a string
String exampleSingleEmailAddress = "john.smith@example.com";
// or for collections
List<String> exampleStringCollection = new List<String>{"john.smith@example.com","jane.doe@example.com"};
List<Contact> exampleContactCollection = [SELECT Id Contact Limit 2];
Example: configure inputs with sources of email addresses:

Reference
Addressees are manually assigned using the following parameters (Type List<> is a Collection):
Name | Type |
---|---|
SendTOthisOneEmailAddress | String |
SendTOthisStringCollectionOfEmailAddresses | List<String> (or Collection of String in Flow) |
SendTOtheEmailAddressesFromThisCollectionOfContacts | List<Contact> (or Collection of Contact in Flow) |
SendTOtheEmailAddressesFromThisCollectionOfUsers | List<User> (or Collection of User in Flow) |
SendTOtheEmailAddressesFromThisCollectionOfLeads | List<Lead> (or Collection of Lead in Flow) |
SendCCthisOneEmailAddress | String |
SendCCthisStringCollectionOfEmailAddresses | List<String> (or Collection of String in Flow) |
SendCCtheEmailAddressesFromThisCollectionOfContacts | List<Contact> (or Collection of Contact in Flow) |
SendCCtheEmailAddressesFromThisCollectionOfUsers | List<Lead> (or Collection of Lead in Flow) |
SendBCCthisOneEmailAddress | String (or Collection of String in Flow) |
SendBCCthisStringCollectionOfEmailAddresses | List<String> (or Collection of String in Flow) |
SendBCCtheEmailAddressesFromThisCollectionOfContacts | List<Contact> (or Collection of Contact in Flow) |
SendBCCtheEmailAddressesFromThisCollectionOfUsers | List<User> (or Collection of User in Flow) |
SendBCCtheEmailAddressesFromThisCollectionOfLeads | List<Lead> (or Collection of Lead in Flow) |
Sender (From)/Reply-To
These seetings determine what addresses the email will appear to be coming from. NOTE: Unless you’ve made special arrangements in your Org, the message will always appear to be coming from (Example): noreply@salesforce.com; on behalf of; Do Not Reply <donotreply.example.com> .
You can either 1) use an OrganizationWideEmailAddress or 2) specify your own Reply-To Email Address and Sender Display Name. If you provide an OrganizationWideEmailAddress, that will take precedence and any Reply-To Email Address and/or Sender Display Name you’ve also provided will be ignored.
Using Organization-Wide Email Address
To use an OrganizationWideEmailAddress , pass the Id of one that you have defined into the action via the “Use This Organization-Wide Email Address Id”. (If you want to get the benefit of Verified sending, you can’t just paste the email address into the Reply-To Email Address field. You have to use the Use This Organization-Wide Email Address Id field.). to find the ID, search the OrgWideEmailAddress object for the appropriate Id. NOTE: you cannot use OrganizationWideEmailAddress and
- In Lightning Setup, go to Organization-Wide Addresses and click Edit on the address you want to use:

2. Examine the URL of this web page. It should look something like this:
3. The Id of the Organization-Wide Email Address is the character between the 2 “%2F” strings. So in the example above, you would extract “0D2560000008PGP” and insert it as an input:

Using Custom Reply-To and/or Sender Display Name
You can change both the “Reply-To” (using the “replyEmailAddress” attribute) and how you wish that name to be displayed (using the senderDisplayName attribute).
The optional In-Reply-To field of the outgoing email identifies the email or emails to which this email is a reply (parent emails) , and the name that appears on the From line of the email. The display name cannot be set if the object associated with a setOrgWideEmailAddressId has defined its DisplayName field.
Subject
Subject can be set directly via the subject parameter. Note that if you choose to use an Email Template Id, the subject will be specified in the template, and the subject parameter in this action will be ignored. Don’t try to use both at the same time. See below for more information on using email templates.
NOTE: If you specify Subject when using an Email Template, that value will override the Template’s Specified Subject. Emails without a subject (either specified or part of the template) will not be sent/delivered.
Body
To specify the body of the email, you can use any of these combinations :
- HTML Body. The body is composed using a text (or rich text) variable, then passed to the Action in the HTMLbody parameter. Flow variables and Global variables can be included for merge in the text at the time of invocation using the standard merge syntax (e.g., {!stringCollectionEmailAddresses} ). You cannot use HTMLBody and a template.
- Advantages. Very quick to create, assemble, and test.
- Disadvantages. May be difficult to find and might require developer (as opposed to Administrator) support to modify. Also, can be very tricky using multi-linguistic sites. (Hint: USE LABELS!!)
- Plain Text Body. Even when you’re sending out an HTML email, a plain text alternative can be desirable. Multi-part MIME (Multipurpose Internet Mail Extensions) bundles together a simplified plain-text version of your email along with the HTML version of your email. You cannot use plainTextBody and a template.
- Both an HTML Body and a plain text body. Use this to send out and HTML email with a bundled plaint-text version. You cannot combine this option with a template.
- Email Templates (Classic or Lightning Email Template). Use Email Templates to save time and standardize email sent by you or others in your organization. Use merge fields or enhanced letterhead if you need them. This has been an evolving function within SalesForce, so if you are unfamiliar with email template options, you may want to review this. Details on how to use EmailTemplates in multilingual environments can be found here.
- Advantages. Consolidates standard communications within the SalesForce email structure (both Classic and Lightning). If you’re using Lightning Email Templates, you have the full range of public, private, and specified sharing capabilities for who can use what and it helps enforce communication standards by making the development of templates and communication more of a communication and policy role rather than a developer or administrator role.
- Disadvantages. Users need to understand the concept of templates and sometimes the differentiation between Classic, Lightning, and (sometimes) VisualForce templates.
- Multi-Lingual Email Templates (only tested with Lightning EmailTemplates).
Body – HTML Body
Rich Text HTML email bodies can use all of the capabilities of Flow’s Text Templates, including Bold, Italics, Underline, Bullets and Numbers, Left/Center/Right justification, URLs, images, fonts, and text size.
To send a rich text (HTML) body, create a resource of type “Text Template” and specify that resource when sending the email with the sendHTMLEmail action.


Body – Plain Text
Even when you’re sending out an HTML email, a plain text alternative can be desirable. Multi-part MIME (Multipurpose Internet Mail Extensions) bundles together a simplified plain-text version of your email along with the HTML version of your email. You cannot use plainTextBody and a template.
To send a plain body text:
- [Optional] Create a text resource, either variable or a formula if you wish to insert line breaks:
- You can just enter text, or specify the resource in the action input values.
Body – Both an HTML Body and a plain text body
[RFU] Previous versions of SalesForce allowed for templates which automatically attached text-only versions in the event a recipient did not desire and/or have the capability to use HTML-based email. As of this writing, it appears the Lightning Email always sends the HTMLBody, but does not attach the plainTextBody.
Signature
You can decide whether or not to include the User email signature if the context user has one configured. The default is true, meaning if the user has a signature it is included in the email unless you specify false. Note: You must enable this parameter AND set it to $GlobalConstant.false if you want to shut it off.

Attachments
You can attach files to your emails. Provide a collection of ContentDocmentLink records. To learn how to attach documents using CDLs, see more here.

Using Email Templates
For a nice introduction on how to use email templates, letterheads and even graphics, you may wish to start here: Configure an Email Letterhead and Template.
You can use Email Templates with this Action.
There are 3 core concepts:
- The Template. The template contains the format of the email (including Letterhead) and syntax for merging fields into that communication. A merge field is a placeholder in an email template or letterhead. When you send the email, the placeholder is replaced with the Salesforce data from the record or records of the people you are emailing. Fields that can be merged include those from the TargetObject, another sObject record, and global variables. NOTE: the merging done by the template system is different from the merging done by Flow, and there is currently limited ability to pass dynamic values from Flow into the template system.
- The Target Object Record. This record reflects the ID of the contact, lead, or user to which the email will be sent. Depending on the type of template you are using, other fields from the TargetObject can also be merged into the template to create the email (e.g., Name). The ID you specify sets the context and ensures that merge fields in the template contain the correct data. For further details, see setTargetObjectId(targetObjectId)
- The Related Record. If you specify a contact for the TargetObject field, you can specify an optional whatId(RecordId) to ensure merge fields in the template contain the correct data. For further details, see setWhatId(whatId)


Using Email Templates
For a standard template, the Template ID and the Template Target Record Id (Recipient) are required. Optionally a related record can be specified using the Template/Activity RecordId(whatId/recordId) Input Value.
Adding Multilingual Email Template Support
SendHTMLEmail provides multi-lingual support within the same flow by allowing a set of related email templates to be created in different languages. In the flow, specify the desired language. To make this work, the names of the email templates must follow some rules:
- Each language localization has its own template with all localizations sharing a common EmailTemplate.Name.
- To differentiate the localizations, add the following text to the EmailTemplate’s Description fieldt: ‘Language=”en_US”‘ (or whatever corresponding to your organization localizations).
For more on how to add localization to an email template set, please refer to Send HTML Email with Multi-Language Support for Lightning Email Templates.
Saving Activity History
You can record the sending of an email as a record activity. This is based on setSaveAsActivity(saveAsActivity) and is Optional. The default value is true. If this is set, you must also specify a valid Related Record ID(recordID) for where the email activity should be saved. This argument only applies if the recipient list is based on targetObjectId or targetObjectIds. If HTML email tracking is enabled for the organization, you will be able to track open rates.

Operational Considerations
This action makes use of the standard Salesforce email infrastructure, the same service that you use when you send a single email directly from a lightning experience page or a classic case feed. As such, any emails you send will be included in your usage, so be aware of the limits and guidelines. (Developer note: this action makes use of the Apex Messaging service API’s.)
This action does not use or involve Email Alerts, which are used in Workflow Rules and exist in Flow as separate actions you can drag into your flow. Be mindful of this so you don’t accidentally confuse the Email Alerts, the Email Templates, and the Flow Text Templates.
Examples
The sendHTMLEmail package ships with two screen flows that can be used to test and demonstrate the action, ‘Send HTML Email Testflow’ and ‘sendHTMLEmail Test – Create Test Templates if Needed’. You do not have to activate these flows to use them. Open ‘Send HTML Email Testflow’ then select “Debug” (or “Run”).

Some of these examples may require prior setup of records. Where necessary, this is described in each of the selected examples. Examples/Tests include:
- Simple Email Text – with To, Sender, Reply-To, Subject, Body (All text)
- Simple Email with Address Collections – Using Address Collections to Send to Multiple Recipients
- Email with Attachments – Simple Email (1) With Attachments
- Email Using Template – An email using a Lightning EmailTemplate
- Multi-Lingual Using Email Templates – An email using a Lightning EmailTemplate selected by language
Choose the example you would like to see and the instructions are in each of the examples. You will also find in these examples the use of Text Templates for formatted Rich Text messages (Example 1), using Plain Text (Example 2), and logging the email as an activity on the related object (Example 5).
To see how the Send HTML Email Action is configured for each of these examples, click on the appropriate Action (they are labeled) and look at the Input Variables. You may also want to look at some of the logic in the setup to those examples for ideas in creating your own flows.

Example 1 – Simple Email Text – with To, Sender, Reply-To, Subject, Body (All text)
This sends out a rich text email predefined as a text template () l to the addressee in [Recipient Email Address] from [ReplyTo Email Address] with the name [Sender Name] using [Subject] and [Body]
All of the above can be created by assigning variables. To create a body with line breaks, use a formula variable (see example variable testPlainTextLineFeeds)
Note: To get the full effect of rich text, edit the formula plainTextBody instead of modifying the field on this screen.
Example 2 – Simple Email with Address Collections
This sends out a simple plaintext email from [ReplyTo Email Address] with the name [Sender Name] using [Subject] and [Body]
All of the above can be created by assigning variables. To create a body with line breaks, use a formula variable (see example variable testPlainTextLineFeeds)
The addressees can be built from multiple collections. This example builds a collection of strings from the two email strings and/or from collections you can set up external to the example flow by creating contacts with names containing the text entered in [Contact Contains Match].
By default, this example builds a collection of strings from the two recipient email addresses and will send all collections to To, CC, and BCC (so 6 emails will be sent – minimum)
Example: Create two contacts with valid email addresses and names containing “testContact”, then specify “testContact” in [Contact Contains Match]
Note: To get the full effect of rich text, edit the formula plainTextBody instead of modifying the field on this screen.
Example 3 – Simple Email with Address Collections
For this example, you will need to create or use a record to which attachments can be made (e.g., a Contact). Create the record and then use the recordId of that record to attach files.
This sends out a simple plaintext email with attachments from uploaded files to the addressee in [Recipient Email Address] from [ReplyTo Email Address] with the name [Sender Name] using [Subject] and [Body]
All of the above can be created by assigning variables. To create a body with line breaks, use a formula variable (see example variable testPlainTextLineFeeds)
Note: This example as distributed uses the formula variable “testPlainTextLineFeeds” to create a plain text body without signature
Example 4 – Email Using Template
This sends out an email using a specified EmailTemplate with the addressee specified through the TargetObjectId and optionally (dependent on your Template) merge fields with an associated object record using that record’s Id.
For this example, you will need to create or use a template. Templates also require that you have a recipient record (targetObjectId) (e.g., Contact, User, . . .) which must also pre-exist. You will be required enter the ID for that record as the (targetObjectId). Additionally if you intend to test merge fields (RelatedTo) with your template, you must also pre-create the related object record and have available the Id for that record as an ID for the Record Object Id (RecordId).
Example 5 – Multi-Lingual Using Email Templates
SendHTMLEmail provides multi-lingual support within the same flow by allowing the language to be specified, then selecting the appropriate template for that language. For this functionality, each language localization has its own template with all localizations sharing a common EmailTemplate.Name. To differentiate the localizations, add a tag to the EmailTemplate.Description field in the format: ‘Language=”en_US”‘ (or whatever corresponding to your organization localizations)
This example uses the template set sendHTMLTest with english (en_US) and spanish (es_MX) versions. If the templates do not exist, this example will automatically create them for you (sendHTMLEmailTest).
You will also need to:
1) Create a Contact (for Target Object) and have its Id available.
2) Create an Account (for Related Record) and have its Id available.
You can, of course, vary the templates and object records to reflect your organization’s needs.
This sends out an email using a specified EmailTemplate with the addressee specified through the TargetObjectId and optionally (dependent on your Template) merge fields with an associated object record using that record’s Id.
For this example, you will need to create or use one or more templates. Templates also require that you have a recipient record (targetObjectId) (e.g., Contact, User, . . .) which must also pre-exist. You will be required enter the ID for that record as the (targetObjectId). Additionally if you intend to test merge fields (RelatedTo) with your template, you must also pre-create the related object record and have available the Id for that record as an ID for the Record Object Id (RecordId).
Reference
Name Or Label | Type | Description |
---|---|---|
contentDocumentAttachments | List<ContentDocumentLink>(or Collection of ContentDocumentLink in Flow) | |
HTMLbody | String | |
orgWideEmailAddressId | String | |
plainTextBody | String | |
Related Record ID(whatId/recordId) | String | If you specify a contact for the targetObjectId field, you can specify an optional whatId as well. This helps to further ensure that merge fields in the template contain the correct data. This is used for merge fields and for associating activities and attachments. |
replyEmailAddress | String | |
saveAsActivity | Boolean | |
SendBCCtheEmailAddressesFromThisCollectionOfContacts | List<Contact>(or Collection of Contact in Flow) | |
SendBCCtheEmailAddressesFromThisCollectionOfLeads | List<Lead>(or Collection of Lead in Flow) | |
SendBCCtheEmailAddressesFromThisCollectionOfUsers | List<User>(or Collection of User in Flow) | |
SendBCCthisOneEmailAddress | String | |
SendBCCthisStringCollectionOfEmailAddresses | List<String>(or Collection of String in Flow) | |
SendCCtheEmailAddressesFromThisCollectionOfContacts | List<Contact>(or Collection of Contact in Flow) | |
SendCCtheEmailAddressesFromThisCollectionOfLeads | List<Lead>(or Collection of Lead in Flow) | |
SendCCtheEmailAddressesFromThisCollectionOfUsers | List<User>(or Collection of User in Flow) | |
SendCCthisOneEmailAddress | String | |
SendCCthisStringCollectionOfEmailAddresses | List<String>(or Collection of String in Flow) | |
senderDisplayName | String | |
SendTOtheEmailAddressesFromThisCollectionOfContacts | List<Contact>(or Collection of Contact in Flow) | |
SendTOtheEmailAddressesFromThisCollectionOfLeads | List<Lead>(or Collection of Lead in Flow) | |
SendTOtheEmailAddressesFromThisCollectionOfUsers | List<User>(or Collection of User in Flow) | |
SendTOthisOneEmailAddress | String | |
SendTOthisStringCollectionOfEmailAddresses | List<String>(or Collection of String in Flow) | |
subject | String | |
Template Language | String | Used in conjunction with Template Name, Finds templates with the name matching Template Name for ‘Language=”xxx_YY”‘ in the Description. Template Selection criteria order first found Name with: 1)If empty, Org LanguageLocaleKey 2)Language found in Description 3)First without ‘Language=”‘ |
Template Name | String | Used in conjunction with Template Language. Finds templates with the name matching Template Name for \’Language=”xxx_YY”\’ in the Description. |
Template Target Record Id | String | If you are passing in a template Id, you need to also pass in the Id of context record. It can be a Contact, Lead, or User. It will determine which data gets merged into the template’ |
templateID | String | |
UseSalesforceSignature | Boolean |
Installation
- 1.33 Unmanaged sendHTMLEmail (with Flow Examples/Tests) – Added documentation, validations, examples)
- 1.33 Unmanaged sendHTMLEmail(No Tests) – No Flow tests or examples (Added documentation, validations)
- 1.32 Unmanaged – Adds Bulkification
Old versions
1.31 Unmanaged
1.2 Unmanaged (attachments are supported using Attachments instead of Content Document Links)
1.0 Unmanaged
1.0 – Managed (requires Winter ’20)