Most of the time, it is best to use the event email functionality within Microsoft Dynamics 365 for Finance and Supply Chain. Other times, it is helpful to send D365 emails directly. In this article, learn how to send D365 emails using X++ code. Notably, the system can create and send an email. Or, an email form can be opened directly within Dynamics. From there, the user can type in the email details, then click the Send button when ready.
Setup
Before you can actually send an email, you need to set up D365 to be able to send emails. This means setting up an email provider. To do this, follow my article on How To Configure Email in D365. Also, consult the Microsoft Documentation.
Email Options
Importantly, there are several different ways to send D365 emails. The best option will be based two things.
- What action or event triggers the email being sent?
- What dynamic data, if any, should be included in your email?
Events
To explain, the out-of-the-box system already has functionality to create and send an email when certain events occur. If you want the emails to be sent automatically when an event occurs, you should use this email option. See my article on How To Send D365 Event Emails.
For example, the system can send an email when an order is placed, shipped, or ready for pickup. There are many more supported events.
Email Templates
Email templates make it easier to send D365 emails. Users can create the HTML layout of the email in advance to ensure it looks professional. But then also add specific placeholders inside the email that the system will replace with context-specific data. The HTML layout is stored in the database, so it can be changed without a code change. Therefore, using an email template in every scenario is highly recommended. See my article on How To Set Up A D365 Email Template.
Email Text
While it is best to leverage the email template functionality most of the time, you can specify the text in the email’s subject and body. This text could be hardcoded, built programmatically, or read from the database. Additionally, a form can be opened to allow the user to enter all the details, then send the email themselves.
Email Text Code Example
The easiest way to understand the differences is to see example code. I will go in reverse order from what I listed above.
Example Code
The code below shows you how to send D365 emails in X++ code.
Fortunately, the system already has two classes that make sending emails very easy.
- SysMailerMessageBuilder helps store all the various pieces that make up an email: From email address, To email address, Subject, and Body.
- SysMailerFactory helps send the email either without user intervention or interactively.
See this runnable class with the example code.
class tutorial_SendEmailMessage
{
public static void main(Args _args)
{
Email toEmailAddress = "test@gmail.com";
str emailSenderName = "John Smith";
str emailSenderAddr = "april@contosoax7.onmicrosoft.com";
str emailSubject = "Hello World";
str emailBody = @'
<!DOCTYPE html>
<html>
<head>
<title>Sample Email</title>
</head>
<body>
<h1>Sample Email</h1>
<p>This is a my sample emails.</p>
</body>
</html>
';
if (toEmailAddress)
{
var messageBuilder = new SysMailerMessageBuilder();
messageBuilder.addTo(toEmailAddress)
.setSubject(emailSubject)
.setBody(emailBody);
if (emailSenderAddr)
{
messageBuilder.setFrom(emailSenderAddr, emailSenderName);
}
SysMailerFactory::sendInteractive(messageBuilder.getMessage());
//SysMailerFactory::sendNonInteractive(messageBuilder.getMessage());
Info(strFmt("Email sent to %1", toEmailAddress));
}
}
}
Explaining The Code
To understand the code, notice the follow things.
First, variables are set at the top with all of the relevant information. Optionally, your code can read this information from a form or a field in a database.
Second, I have hard-coded the email body in the code above. This, too, can be read from a database. (See Email Templates in the next section). To make it so I could copy the HTML, I use this format:
str emailBody = @' <your email body code goes> ';
By putting the ‘@‘ symbol before the first single quote, followed by a single quote at the end, the code can span multiple lines and include double quotes in the text.
Also, it is helpful to use an outside code HTML to confirm everything looks correct before putting it in the code. One option is to use the online W3schools browser editor here.
Note, you do not need to use HTML code. You can just use plain text. However, most professional emails leverage HTML’s formatting benefits.
Third, the SysMailerFactory class has two different methods that can be called. Specifically, the method sendNonInteractive will send the email immediately using all of the specified information. Alternatively, the sendInteractive method will open a dialog form, allowing the user to make changes.

When ready, the user can click the ‘Send‘ button to send the email.

Email Templates Code Example
In order to fully run this example, you need to create the email template, then copy and run the code to send the email.
Create The Email Template
Instead of hard-coding the email body, email templates let you edit the email in a form. See my article for more details on how to set these up. But this is a short summary.
Go to Organization administration>Setup>Organization email templates.

On this form, first create an ‘EmailID‘ name. Second, add a new Email message content row in the grid. Third, click the ‘Email message’ button. Finally, upload an .html file containing the email body.

To allow you to follow along, I have written this runnable class (job), which will create an email template for you. In Visual Studio, copy the following code into a runnable class (job), then run the code.
class tutorial_CreateEmailTemplateSendEmail
{
public static void main(Args _args)
{
SysEmailTable sysEmailTable;
SysEmailId emailID = "SendEmail"; //Usually this would come from a parameter.
LanguageId languageID = "en-us"; //Usually this would come from a parameter.
sysEmailTable = SysEmailTable::find(emailID);
if (!sysEmailTable)
{
sysEmailTable.EmailId = emailID;
sysEmailTable.Description = "Send email template";
sysEmailTable.DefaultLanguage = "en-us";
sysEmailTable.Priority = eMailPriority::Normal;
sysEmailTable.SenderAddr = "april@contosoax7.onmicrosoft.com";
sysEmailTable.SenderName = "Dynamics 365 Musings Orders";
sysEmailTable.BatchGroupId = "";
sysEmailTable.insert();
Info(strfmt("Added sysEmailTable record with EmailID %1",emailID));
}
SysEmailMessageTable sysEmailMessageTable = SysEmailMessageTable::find(emailID, languageID);
if (!sysEmailMessageTable)
{
sysEmailMessageTable.EmailId = emailID;
sysEmailMessageTable.LanguageId = languageID;
sysEmailMessageTable.LayoutType = SysEmailLayoutType::StaticLayout;
sysEmailMessageTable.Subject = "Deal on Item %itemid%";
str mailBody = @'
<html>
<head>
<title>Custom message</title>
</head>
<body>
<div class="container" style="" width:600px; margin:0 auto;>
<p>Dear %customername%,</p>
<p>
We want to let you know about a deal that is happening right now on itemId %itemid%.
</p>
<h2 style="" font-family:Arial; line-height:1.5em;>Thank you for your business<br /></h2>
<div style="" max-width:600px;>
<table
style=""
width:100%;
max-width:600px;
min-width:300px;
font-family:Arial;
font-size:.8em;
font-weight:normal;
color:#333344;
text-align:left;
border-top:#D1D2D4
1px
dotted;
>
<tr>
<td style="" width:50%; max-width:400px;>
<p>
Your Business Name<br />
555 Main Street<br />
Boulder, CO 80303
</p>
</td>
<td style="" width:50%; max-width:400px;>
<p>
<a href="" tel:800.555.1234 style="" text-decoration:none;>800.555.1234</a><br />
<a href="mailto:sample@gmail.com" style="" text-decoration:none;
>sample@gmail.com</a
>
<br />
<a href="https://www.dynamics365musings.com" style="" text-decoration:none;>dynamics365musings.com</a>
<br />
</p>
</td>
</tr>
</table>
</div>
</div>
</body>
</html>
';
sysEmailMessageTable.Mail = mailBody;
sysEmailMessageTable.insert();
Info(strfmt("Added sysEmailMessageTable record with EmailID %1",emailID));
}
}
}
After running this job, a new email template will be created named ‘SendEmail‘.
Notice, there are two placeholders in the text: %customername% and %itemID%. These will be replaced by values when the system sends the email.
Send Email Template Code
Finally, below is the code that uses the email template to send D365 emails.
class tutorial_SendEmail
{
public static void main(Args _args)
{
SysEmailId emailId = "SendEmail"; //Usually this would come from a parameter.
LanguageId languageID = "en-us"; //Usually this would come from a parameter.
Email toEmailAddress = "test@gmail.com"; //Replace with your email address.
// Tokens for email template replacement
#define.CustomerName('customername')
#define.ItemId('itemid')
Map templateTokens = new Map(Types::String, Types::String);
templateTokens.insert(#CustomerName, "John Smith");
templateTokens.insert(#ItemId, "1000");
str emailSenderName;
str emailSenderAddr;
str emailSubject;
str emailBody;
if (emailId)
{
[emailSubject, emailBody, emailSenderAddr, emailSenderName] = tutorial_SendEmail::getEmailTemplate(emailId, languageID);
if (emailBody)
{
var messageBuilder = new SysMailerMessageBuilder();
str emailSubjectWithPlaceholdersReplaced = SysEmailMessage::stringExpand(emailSubject, SysEmailTable::htmlEncodeParameters(templateTokens));
str emailBodyWithPlaceholdersReplaced = SysEmailMessage::stringExpand(emailBody, SysEmailTable::htmlEncodeParameters(templateTokens));
messageBuilder.addTo(toEmailAddress)
.setSubject(emailSubjectWithPlaceholdersReplaced)
.setBody(emailBodyWithPlaceholdersReplaced);
if (emailSenderAddr)
{
messageBuilder.setFrom(emailSenderAddr, emailSenderName);
}
//SysMailerFactory::sendInteractive(messageBuilder.getMessage());
SysMailerFactory::sendNonInteractive(messageBuilder.getMessage());
Info(strFmt("Email sent to %1 using email template %2.", toEmailAddress, emailId));
}
}
}
static container getEmailTemplate(SysEmailId _emailId, LanguageId _languageId)
{
var messageTable = SysEmailMessageTable::find(_emailId, _languageId);
var emailTable = SysEmailTable::find(_emailId);
if (!messageTable && emailTable)
{
// Try to find the email message using the default language from the email parameters
messageTable = SysEmailMessageTable::find(_emailId, emailTable.DefaultLanguage);
}
if (messageTable)
{
return [messageTable.Subject, messageTable.Mail, emailTable.SenderAddr, emailTable.SenderName];
}
else
{
warning(strfmt("No template with email %1 was found.",_emailId));
return ['', '', emailTable.SenderAddr, emailTable.SenderName];
}
}
}
To explain, the code above has most of the same code as earlier. However, the system first gets the SysEmailMessageTable and the SysEmailTable that match the email template ID we want to use.
Second, the system stores a map of name/value pairs. The system finds the placeholder in the email template that matches the ‘name’, and replaces it with the corresponding ‘value using this code:
SysEmailMessage::stringExpand(emailBody, SysEmailTable::htmlEncodeParameters(templateTokens));
Interestingly, it can do this on the ‘Subject‘ as well as ‘Body‘ of the email. This allows the subject of each email to contain dynamic data as well.
Finally, the system uses the SysMailerFactory class to send the email.

To summarize, a developer can build their own email body string. However, using the email template leverages existing functionality, making it easier to code, while also allowing for the email body to be changed through a form.
Event Code Example
In order to send D365 emails when an event occurs, the system already has code that inserts records into the RetailEventNotificationAction table. After that, a batch job generates an email using the email template associated with that event in the form Retail and commerce>Headquarters setup>Commerce email notification profile.

Since there are specific places in the code for each event, developers should typically not add more code for the same event. However, they may want to create their own custom events. I will cover that in a separate article.
That said, if you are curious, the way the system creates a record in the RetailEventNotificationAction table, which ultimately sends an email, is by calling the method ‘insertRetailOENAction‘ and sending in the ‘notification type‘, and the relevant information, usually a salesTable record.

Microsoft Documentation
Here is the Microsoft documentation on this topic. This article also includes other examples of emails being sent using X++ in the base code.
Conclusion
Microsoft Dynamics 365 for Finance and Supply Chain already has several options for sending emails. Leverage the base functionality to save time. Additionally, it will create a more consistent email setup for the end user. That said, there may still be instances where it is best to send D365 emails using your own X++ code.
Leave a Reply