D365: Send email in X++ using email templates

Product:

Dynamics 365 for Finance and Operations

Purpose:

The purpose of this document is to demonstrate how we can send emails in X++ using built-in email templates. For demonstration purposes we’ll be using standard email template CnfmOrder. This email template is used to send email to customer when a sales order is confirmed.

Business requirement:

Automate sending email to customer’s contact when a sales order is confirmed.

Prerequisites:

Email parameters must be configured.

Development:

You can find built-in email templates in the system under:

Organization administration > Setup > Email templates

Note that we have keyed in the sender email field as it will be used in the code as the “Sender”.

image

You can use the following code to automatically send email using X++. The given code also handles inserting placeholder values in the email template. It uses salesId variable which is a global class member and is provided by the caller class.

public void generateEmail()
{
   // Tokens for email template replacement
   #define.SalesIdToken('salesid')
   #define.CustNameToken('customername')
   #define.DeliveryAddress('deliveryaddress')
   #define.CustomerAddress('customeraddress')
   #define.ShipDate('shipdate')
   #define.ModeOfDelivery('modeofdelivery')
   #define.Charges('charges')
   #define.Discount('discount')
   #define.Tax('tax')
   #define.Total('total')
   #define.LineProductName('lineproductname')
   #define.LineProductDesc('lineproductdescription')
   #define.LinePrice('lineprice')
   #define.LineQuantity('linequantity')
   #define.LineNetAmount('linenetamount')

   SalesTable salesTable;
   SalesLine salesLine;
   CustTable custTable;
   ContactPerson contactPerson;
   SalesTotals salesTotals;
   SysEmailId emailId;
   Map templateTokens;

   str emailSenderName;
   str emailSenderAddr;
   str emailSubject;
   str emailBody;
   str emailToAddress;

   salesTable = SalesTable::find(salesId);
   salesLine = SalesLine::find(salesTable.SalesId);
   custTable = CustTable::find(salesTable.CustAccount);
   contactPerson = ContactPerson::find(salesTable.SixCustContactPersonId);
   salesTotals = SalesTotals::construct(salesTable);
   emailToAddress = contactPerson.email();
   emailId = salesTable.SixSysEmailId;

   templateTokens = new Map(Types::String, Types::String);
   templateTokens.insert(#SalesIdToken, salesTable.SalesId);
   templateTokens.insert(#CustNameToken, custTable.name());
   templateTokens.insert(#DeliveryAddress, salesTable.deliveryAddress().Address);
   templateTokens.insert(#CustomerAddress, custTable.address());
   templateTokens.insert(#ShipDate, strFmt("%1", salesTable.ShippingDateRequested));
   templateTokens.insert(#ModeOfDelivery, strFmt("%1", salesTable.DlvMode));
   templateTokens.insert(#Charges, strFmt("", salesTotals.totalMarkup()));
   templateTokens.insert(#Discount, strFmt("", salesTotals.totalEndDisc()));
   templateTokens.insert(#Tax, strFmt("", salesTotals.totalTaxAmount()));
   templateTokens.insert(#Total, strFmt("", salesTotals.totalAmount()));
   templateTokens.insert(#LineProductName, salesLine.itemName());
   templateTokens.insert(#LineProductDesc, salesLine.itemLineDisc());
   templateTokens.insert(#LinePrice, strFmt("%1", salesLine.SalesPrice));
   templateTokens.insert(#LineQuantity, strFmt("%1", salesLine.SalesQty));
   templateTokens.insert(#LineNetAmount, strFmt("%1", salesLine.LineAmount));
      
   if (emailId)
   {
    [emailSubject, emailBody, emailSenderAddr, emailSenderName] =
      SixCustVendEmailController::getEmailTemplate(emailId, custTable.languageId());
   }
      
   var messageBuilder = new SysMailerMessageBuilder();
   messageBuilder.addTo(emailToAddress)
    .setSubject(emailSubject)
    .setBody(SysEmailMessage::stringExpand(
      emailBody, SysEmailTable::htmlEncodeParameters(templateTokens)));

   if (emailSenderAddr)
   {
    messageBuilder.setFrom(emailSenderAddr, emailSenderName);                
    SysMailerFactory::getNonInteractiveMailer().sendNonInteractive(messageBuilder.getMessage());
   }
}

The generateEmail() method calls the following method to get the email template:

protected 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("@SYS135886"); // Let the user know we didn't find a template
      return ['', '', emailTable.SenderAddr, emailTable.SenderName];
   }
}

Once triggered, the code sends out the email through the configured SMTP server and can be found in the inbox:

2 thoughts on “D365: Send email in X++ using email templates

Add yours

  1. This blog is awesome, only issue is it is sending email only with the first po line.

    Please suggest how to print all the po lines

    Thank
    Kathir

  2. Can you pls help me how to achieve this requirement–need to send email notifications prior 3 days or less before work order start date and after completed that work order we need to send the work completed status with upcoming work order info to responsible group I’d using email template

Leave a comment

Create a free website or blog at WordPress.com.

Up ↑