Timely confirmations and details are essential for building customer trust. In this article, learn how to send D365 event emails. After a customer or business takes an action, an email confirmation of that action is often expected. Learn how to associate an email template with a predefined event, such as an order being placed, shipped, or ready for pick up. The system will then send a D365 event email in the format of the email template whenever that event occurs.
Transactional Events
In Microsoft Dynamics 365 for Finance and Supply Chain, several processes trigger D365 event emails. You can set up an email template for each event or notification type. This list shows the events that trigger an email notification.
- Order created – When the system creates a new sales order.
- Order confirmed – When the system generates an order confirmation.
- Picking completed – When the system marks as complete a picking list for an order.
- Packing completed – When the system generates a packing slip document for an order.
- Order ready for pickup – When the system marks an order as packedand sets the delivery mode to Customer pickup on one or more order lines.
- Order Shipped – When the system invoices an order that has a non-store-pickup mode of delivery.
- Order invoiced – When the system invoices an order.
- Issue gift card – When the system invoices a sales order that contains a product of the gift card type.
- Order cancellation – When the system cancels an order.
- Customer created – When the system creates a new customer entity. To enable this notification, go to Retail and Commerce>Headquarters setup>Parameters>Commerce parameters. Then, on the General tab, set the Email notification profile to a profile that has a ‘customer created‘ notification type.
- B2B prospect approved – When the system approves a prospect’s onboarding request.
- B2B prospect rejected – When the system rejects a prospect’s onboarding request.
See Microsoft’s documentation for a complete list.
Commerce Email Notification Profiles
To associate an email template with D365 event emails, also known as notification types, go to Retail and commerce>Headquarters setup>Commerce email notification profile. On this form, specify the email template ID that should be used for each email notification type.

First, click the ‘New‘ button at the top of the form, and set the Email notification profile, Description, and Active fields.
Second, in the ‘Retail event notification settings‘ grid, click the ‘New‘ button.
Third, set the ‘Email notification type‘ field to one of the supported events.

Fourth, set the ‘Email ID’ to an email template. Until you create an email template, there will not be any options to select.

Create A D365 Email Template
To create an email template, follow the steps in my article Set Up A D365 Email Template. Businesses can work with a web developer to help create an email template for each communication event. Then, return to the Email notification profiles form to associate the email template ID with the email notification type.
Email Template Placeholders
In order for the system to replace the placeholder text with values from the order, code must exist to tell the system which value from the order to use. A developer can modify the code to add additional placeholders that do not already exist. Additionally, placeholders can also be added to display custom fields added by developers. I will write an article soon on how to do this.
Order Header Placeholders
For now, see this list of the most common sales order header placeholders you can use in most events. See the Microsoft documentation for additional placeholders that can only be used for certain events.
- customername = salesOrder.SalesName
- customeremailaddress = salesOrder.Email
- salesid = salesOrder.SalesId
- deliveryaddress = salesOrder.deliveryAddressing()
- deliveryname = this.getDeliveryName(salesOrder)
- customeraddress = CustTable::find(salesOrder.CustAccount).address()
- deliverydate = RetailENInfo::formatDatetimeData(salesOrder.deliveryDateDisplay(), languageId)
- shipdate = RetailENInfo::formatDatetimeData(salesOrder.ShippingDateRequested, languageId)
- modeofdelivery = dlvMode::find(salesOrder.DlvMode).Txt
- orderconfirmationid = salesOrder.retailSalesTable().ChannelReferenceId
- storeaddress = InventLocation::find(store.inventLocation).address()
- storeopenfrom = time2str(store.openFrom, TimeSeparator::Colon, TimeFormat::AMPM)
- storeopento = time2str(store.openTo, TimeSeparator::Colon, TimeFormat::AMPM)
- storename = store.name()
- charges = RetailENInfo::formatNumericDataInternal(totalCharge, languageId, currencySymbol)
- tax = RetailENInfo::formatNumericDataInternal(totalTaxAmount, languageId, currencySymbol)
- total = RetailENInfo::formatNumericDataInternal(totalAmount, languageId, currencySymbol)
- discount = RetailENInfo::formatNumericDataInternal(totalDiscount, languageId, currencySymbol)
- ordernetamount = RetailENInfo::formatNumericDataInternal(totalAmount – totalTaxAmount – totalCharge, languageId, currencySymbol)
- customeraccountpayment_accountnumber = customerAccountForPayment
- customeraccountpayment_amount = customerAccountAmount
Order Line Placeholders
These are the Sales Line related records:
- lineproductname = EcoResProductTranslation::getNameOrDefaultName(productMasterRecId, languageId)
- lineproductdescription = EcoResProductTranslation::getDescriptionOrDefaultDescription(productMasterRecId, languageId)
- productid = int642Str(productRecId)
- lineproductrecid = int642Str(productRecId)
- lineitemid = salesLine.ItemId
- lineproductvariantid = salesLine.RetailVariantId
- lineproductvariantinfo = RetailProductPropertyManager::getRetailVariantDescription(salesLine.ItemId, salesLine.RetailVariantId, languageId)
- linequantity = RetailENInfo::formatQtyData(qty, languageId, salesLine.SalesUnit)
- linequantitypicked = RetailENInfo::formatQtyData(qtyPicked, languageId, salesLine.SalesUnit)
- linequantitypacked = RetailENInfo::formatQtyData(qtyPacked, languageId, salesLine.SalesUnit)
- linequantityshipped = RetailENInfo::formatQtyData(qtyShipped, languageId, salesLine.SalesUnit)
- linequantity_withoutunit = RetailENInfo::formatQtyData(qty, languageId, ”)
- linequantitypicked_withoutunit = RetailENInfo::formatQtyData(qtyPicked, languageId, ”)
- linequantitypacked_withoutunit = RetailENInfo::formatQtyData(qtyPacked, languageId, ”)
- linequantityshipped_withoutunit = RetailENInfo::formatQtyData(qtyShipped, languageId, ”)
- lineprice = RetailENInfo::formatNumericDataInternal(salesLine.SalesPrice, languageId, currencySymbol)
- linediscount = RetailENInfo::formatNumericDataInternal(salesLine.LineDisc, languageId, currencySymbol)
- linenetamount = RetailENInfo::formatNumericDataInternal(salesLine.LineAmount, languageId, currencySymbol)
- linedeliverydate = RetailENInfo::formatDatetimeData(salesLine.deliveryDate(), languageId)
- lineshipdate = RetailENInfo::formatDatetimeData(salesLine.ShippingDateRequested, languageId)
- linepickupdate = RetailENInfo::formatDatetimeData(salesLine.ShippingDateRequested, languageId)
- linedeliverymode = dlvMode::find(salesLine.DlvMode).Txt
- linedeliveryaddress = salesLine.deliveryAddress().Address
- lineunit = salesLine.SalesUnit
- availablebalance = num2Str(retailGiftCardTransactions.Amount, 0, 17, 1, 3)
- giftcardnumber = retailGiftCardTransactions.CardNumber
- upcominginventavaildate = MCRRetailOENInfo_FTCNotice::getUpcomingInventAvailDate(salesLine)
- giftcardnumber = retailExternalGiftCard.CardNumber
- giftcardpin = retailExternalGiftCard.Pin
- giftcardexpiration = retailExternalGiftCard.Expiration
- availablebalance = RetailENInfo::formatNumericDataInternal(salesLine.LineAmount, languageId, currencySymbol)
- giftcardnumber = mcrSalesLine.GiftCardNumber
- giftcardrecipientname = mcrSalesLine.GiftCardRecipientName
- giftcardbuyername = mcrSalesLine.GiftCardBuyerName
- giftcardmessage = mcrSalesLine.GiftCardGiftMessage
- linepickuptimeslot = time2str(retailSalesLine.PickupStartTime, TimeSeparator::Colon, TimeFormat::AMPM) + ‘-‘ + time2str(retailSalesLine.PickupEndTime, TimeSeparator::Colon, TimeFormat::AMPM)
Commerce Parameters
After setting up the email notification profile, and associating events with email templates, now tell the system which email notification profile to use.
First, go to Retail and Commerce>Headquarters setup>Parameters>Commerce parameters.
Second, on the General tab, set the ‘Email notification profile’ field to the profile you set up.

Set Up Email Server
Before testing this functionality, an email server must be configured in the system. To configure an email server, follow my article on How To Configure Email In D365 to send emails.
Set Up Recurring Batch Job
When an event occurs where an email should be sent out, the system creates a record in a staging table with the email information. Then, a batch job runs and processes those records and sends the emails.
To configure the batch job, go to Retail and Commerce>Retail and Commerce IT>Email and notifications>Send email notification.
In the dialog that opens, ensure the ‘Batch processing’ flag is checked. Then, click the ‘Recurrence’ button to set up how often the batch job should run. For example, you could configure it to run every 5 minutes. Finally, click the ‘ok’ button to create the recurring batch job.

Test With An Example
Now that you understand the relationship between an email notification profile and an organizational email template, let us review an example.
Setup
First, navigate to Retail and Commerce>Headquarters setup>Parameters>Commerce parameters. Select and/or remember the value set in the field ‘Email notification profile‘ on the General tab.

Second, navigate to Retail and commerce>Headquarters setup>Commerce email notification profile. Select the profile that was specified in the commerce parameters form. Then locate, or create if it doesn’t already exist, the record in the grid with ‘Email notification type’ set to ‘Customer created‘.

Third, ensure this record has a corresponding ‘Email ID‘. If not, create one and select an email template. In this example, the Email ID is set to ‘CUST_create‘, which exists in the Microsoft demo data.
Email Template Setup
Optionally, click on the blue text of the email ID to drill into the email template.

Then, to see what it looks like, click on the ‘Edit‘ button or ‘Email message‘ button.

In this example, notice this email template has a placeholder for %customername% and %customeremailaddress%. The system will replace these with information from the customer.

If you want to use the same example, copy the text below into Notepad. Next, save the file with a file extension of .html. Then, click the Browse button on the ‘Upload email template‘ dialog box and select the file.
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "https://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style type="text/css" nonce="">
body,
td,
div,
p,
a,
input {
font-family: arial, sans-serif;
}
</style>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Your Fabrikam order details</title>
<style type="text/css" nonce="">
body,
td {
font-size: 13px;
font-family: "Segoe UI", "Segoe", "Tahoma", "Verdana", "Arial", "sans-serif";
margin: 0px;
border: 0px;
}
a:link,
a:active {
color: #1155cc;
text-decoration: none;
}
a:hover {
text-decoration: underline;
cursor: pointer;
}
a:visited {
color: #6611cc;
}
img {
border: 0px;
}
.logo {
left: -7px;
position: relative;
}
.label {
font-weight: bolder;
}
.totalslabel {
text-align: right;
padding-right: 20px;
}
.headerprops {
margin-bottom: 4px;
}
.linevalue {
text-align: right;
}
</style>
</head>
<body style="background-color: #eeeeee; color: #1a1a1a">
<table
style="margin-top: 20px; padding: 0px 20px 20px 20px; width: 640px; background-color: #fff"
align="center"
>
<tbody>
<tr>
<td>
<table style="width: 100%; margin-bottom: 10px">
<tr>
<td style="text-align: right"></td>
</tr>
<tr>
<td style="text-align: center; padding-top: 10px">
<!-- Logo -->
<a href="https://sales1.commerce.dynamics.com/"
><img
width="180"
style="border-style: none; outline: none"
src="https://images-us-prod.cms.commerce.dynamics.com/cms/api/dbsbfgcfvq/imageFileData/MAaq0?pubver=1"
alt="Fabrikam Online logo"
/></a>
</td>
</tr>
<tr>
<td style="text-align: center">
<h1 style="font-family: "Segoe UI light"; margin-bottom: 10px">
<!-- Subject -->
Thank you for creating an account
</h1>
</td>
</tr>
<tr>
<td style="text-align: center; padding: 0px 100px 10px 100px">
<!-- Instructions -->
<p>
Hello <b>%customername%</b>. Thank you for creating your account with Fabrkiam
Inc., we're happy to have you! A Fabrikam membership has its rewards - we value
our customers!
</p>
<p>
We will keep you informed about order status by sending mail to
<b>%customeremailaddress%</b>.
</p>
</td>
</tr>
<tr>
<td style="text-align: center" align="center"></td>
</tr>
</table>
</td>
</tr>
<!-- Footer -->
<tr>
<td>
<table style="background-color: #eee; padding: 0px 5px">
<tr>
<td>
This email was sent to %customeremailaddress%. Fabrikam respects your privacy. See
our online
<a style="color: #1570a6" href="https://aka.ms/commerceemailsetup" target="_blank"
>Privacy Statement</a
>.<br /><br />
Fabrikam Corporation, One Fabrikam Way, Redmond, WA, 98052, USA
</td>
</tr>
<tr>
<td style="font-size: smaller">
Notification type: <b>Customer created</b><br />
Mode of delivery: <b>n/a</b>
</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
</body>
</html>
Create A Customer
Now that the email template and notification profile is set up, create a customer to trigger an email.
First, navigate to Accounts Receivable>Customers>All customers.
Second, click the ‘New‘ button. When the dialog box opens, fill out the information to create a new customer. Note, it is important to fill out the ‘Email address’ field so that the customer has an email. Then, click ‘Ok‘.

To clarify, the system will use the customer’s primary email address to send the ‘new customer’ email to. If you forget to set this, or want to change it, go to the ‘Contact information’ fast-tab on the customer details page, and add a new primary email address. Ensure you check the ‘Primary’ flag. In this case, the system may have already created the email, making the change too late. But it depends on the timing of when the batch job runs.

Third, behind the scenes, creating the customer will create a record in the RetailEventNotificationAction table. The system now needs to process the staged record and send the email. If you have set up a recurring batch job, you simply need to wait for it to run. Alternatively, run the job immediately. Navigate to Retail and Commerce>Retail and Commerce IT>Email and notifications>Send email notification.
Finally, check the customer’s email, and open the email.

Small Bug
In the above email, the system replaced the placeholder %customername% with the customer’s name. However, the placeholder %customeremailaddress% was not. The reason for this is that the demo data is no longer accurate.
To explain, the ‘customer creation’ event uses a class named RetailENInfo_CustomerCreated, which extends the base class RetailENInfo. The class RetailENInfo_CustomerCreated has a placeholder for ‘customername‘. But neither this class nor the RetailENInfo class has a placeholder for ‘customeremailaddress‘.

However, there is a new class ‘RetailOENInfo‘ that supports more placeholders than the ‘RetailENInfo‘ class. If the RetailENInfo_CustomerCreated class were changed to extend RetailOENInfo, this email template would support ‘customeremailaddress‘.

Conclusion
Throughout the lifecycle of working with a customer, there are many events where communication is both helpful and expected. Microsoft Dynamics 365 for Finance and Supply Chain supports many events out of the box. Set up appropriate branded email templates with relevant, timely data to increase value for your customers.