This content is archived. See latest version here

Last updated: Oct 21 2014

This guide details how to leverage the notification/template engine to have EPiServer Commerce automatically send out e-mail notifications for instance for new orders, customer registrations, and e-mail forms. The notification/template engine is used to generate different types of templated content, and is mostly used to create personalized e-mails for customers regarding orders.

How it works

The template engine itself is based on the ASP.NET 2.0 Provider Model, and can be easily customized or replaced without the need to access any of the framework source code. The default implementation is an XSL based template provider, allowing for the creation of templates using XML Stylesheet Language(XSL).

Refer also to Configuring Notifications for related information.

Classes referred to here are available in the following namespaces:

Key classes and files

  • TemplateService.cs - loads the appropriate template provider and returns formatted text for the e-mail.
  • CheckoutWizardModule.ascx - uses the TemplateService to generate the text for order-related e-mails, see the SendEmails methods.
  • XslTemplateProvider.cs - custom template provider included.
  • TemplateProvider.cs - base class from which all template providers must inherit.

Quick overview

The web.config file of your public/admin sites will contain this section:

<system.net>
<mailSettings>
<smtp>
<network host="localhost"/>
</smtp>
</mailSettings>
</system.net>

You can add a user name and password in there as well as authentication for the SMTP server if required. Refer to MSDN for more information on configuration of e-mail settings.

Example: configuring e-mail notifications

XML
<configuration>
<configSections>
<sectionGroup name="FrameworkProviders">
...
<section name="templateService" type="Mediachase.Commerce.Engine.Template.TemplateProviderSection, 
Mediachase.Commerce"/>
</sectionGroup>
...
<FrameworkProviders>
...

<providers>
<add name="XslTemplateProvider" type="Mediachase.Commerce.Engine.Template.Providers.XslTemplateProvider, 
Mediachase.Commerce" applicationName="eCommerceFramework" templateSource="c:\templates\{0}\{1}.xsl"/>
</providers>
</templateService>
</FrameworkProviders>

The templateSource attribute shows how the template name and CultureInfo parameters are used. CultureInfo name is used for the folder name containing the templates for that language. The template name is used with an .xsl extension to specify the file name. An example of the resulting file path for a template in english (CultureInfo name = "en-us"), for the order confirmation (template name = "order-purchaseorder-confirm"), where your templateSource setting is "E:\Template{0}{1}.xsl" would be: E:\Template\en-us\order-purchaseorder-confirm.xsl

Place the PublicLayer\Templates\en-us items in the directory in the template source, these are the template e-mails you will need to customize.

Template service

An example of calling the TemplateService can be found in the CheckoutWizardModule control. Relevant data, including the PurchaseOrder object are placed in a dictionary, and passed to the TemplateService.Process() method with the name of the template, and a CultureInfo instance representing the desired/current culture. The Process() method returns the formatted custom text.

Example: sending out e-mails

C#
private void SendEmails(PurchaseOrder order, string email)
        {
            // Add input parameter
            Dictionary<string, object> dic = new Dictionary<string, object>();
            dic.Add("OrderGroup", order);

            // Send out emails
            // Create smtp client
            SmtpClient client = new SmtpClient();

            MailMessage msg = new MailMessage();
            msg.From = new MailAddress(StoreEmail, StoreTitle);
            msg.IsBodyHtml = true;

            // Send confirmation email
            msg.Subject = String.Format("{1}: Order Confirmation for {0}", order.CustomerName, StoreTitle);
            msg.To.Add(new MailAddress(email, order.CustomerName));
            msg.Body = TemplateService.Process("order-purchaseorder-confirm", Thread.CurrentThread.CurrentCulture, dic);

            // send email
            client.Send(msg);

            msg = new MailMessage();
            msg.From = new MailAddress(StoreEmail, StoreTitle);
            msg.IsBodyHtml = true;

            // Send notify email
            msg.Subject = String.Format("{1}: Order Notification {0}", order.TrackingNumber, StoreTitle);
            msg.To.Add(new MailAddress(StoreEmail, StoreTitle));
            msg.Body = TemplateService.Process("order-purchaseorder-notify", Thread.CurrentThread.CurrentCulture, dic);

            // send email
            client.Send(msg);
        }

The following code is taken from the CheckoutWizard.ascx.cs in the front end, but can be applied to the back end as well. The template service replaces the placeholders with the proper text, and you can add your own files to be used with the template service as well.

Template provider

The XSL/XMLTemplate Provider renders templates using a set of XSL files. It expects that all the parameters passed in the dictionary context can be serialized to xml. It then looks in the path specified in the configuration file (templateSource property) for the specific xsl. If it cannot find the file in the language specific folder, it will try to fall back and look in the "default" folder.

Example: XMLgenerated when PurchaseOrder is passed to the provider

XML
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="en-us/order-confirm.xsl" type="text/xsl"?>
<ContextDoc>
  <PurchaseOrder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Created>2008-05-15T12:30:02.17</Created>
    <Modified>2008-05-15T12:30:02.17</Modified>
    <OrderForms>
      <OrderForm>
        <Created>2008-05-15T12:29:39.013</Created>
        <Modified>2008-05-15T12:29:39.013</Modified>
        <Shipments>
          <Shipment>
            <Created>2008-05-15T12:30:01.78</Created>
            <Modified>2008-05-15T12:30:01.78</Modified>
            <Discounts />
            <OrderGroupId>131</OrderGroupId>
            <OrderFormId>141</OrderFormId>
            <ShippingMethodId>17995798-a2cc-43ad-81e8-bb932f6827e4</ShippingMethodId>
            <ShippingMethodName>Online Download</ShippingMethodName>
            <ShippingAddressId>Home</ShippingAddressId>
            <ShipmentTrackingNumber />
            <ShipmentTotal>10.0000</ShipmentTotal>
            <ShippingDiscountAmount>0.0000</ShippingDiscountAmount>
            <Status />
            <LineItemIds />
          </Shipment>
        </Shipments>
        <Payments>
          <Payment xsi:type="CreditCardPayment">
            <Created>2008-05-15T12:29:39.513</Created>
            <Modified>2008-05-15T12:29:39.513</Modified>
            <OrderFormId>141</OrderFormId>
            <OrderGroupId>131</OrderGroupId>
            <BillingAddressId />
            <PaymentMethodId>e2dff5b7-8ec1-4f14-91a1-357c1bb968a1</PaymentMethodId>
            <PaymentMethodName>Pay By Credit Card</PaymentMethodName>
            <CustomerName />
            <Amount>10.0000</Amount>
            <PaymentType>CreditCard</PaymentType>
            <ValidationCode />
            <AuthorizationCode />
            <Status />
            <CardType />
            <CreditCardNumber />
            <CreditCardSecurityCode />
            <ExpirationMonth>7</ExpirationMonth>
            <ExpirationYear>2009</ExpirationYear>
          </Payment>
        </Payments>
        <LineItems>
          <LineItem>
            <Created>2008-05-15T12:29:39.373</Created>
            <Modified>2008-05-15T12:29:39.373</Modified>
            <Discounts />
            <OrderFormId>141</OrderFormId>
            <OrderGroupId>131</OrderGroupId>
            <Catalog>Everything2</Catalog>
            <CatalogNode>Everything</CatalogNode>
            <ParentCatalogEntryId />
            <CatalogEntryId>thecode</CatalogEntryId>
            <Quantity>2.0000</Quantity>
            <MinQuantity>1.0000</MinQuantity>
            <MaxQuantity>100.0000</MaxQuantity>
            <PlacedPrice>0.0000</PlacedPrice>
            <ListPrice>100.0000</ListPrice>
            <LineItemDiscountAmount>0.0000</LineItemDiscountAmount>
            <OrderLevelDiscountAmount>0.0000</OrderLevelDiscountAmount>
            <ShippingAddressId>Home</ShippingAddressId>
            <ShippingMethodName>Online Download</ShippingMethodName>
            <ShippingMethodId>17995798-a2cc-43ad-81e8-bb932f6827e4</ShippingMethodId>
            <ExtendedPrice>200.0000</ExtendedPrice>
            <Description />
            <Status />
            <DisplayName>Samsung LN52A650 52-inch 1080p 120Hz LCD HDTV with RED Touch of Color</DisplayName>
            <AllowBackordersAndPreorders>false</AllowBackordersAndPreorders>
            <InStockQuantity>0.0000</InStockQuantity>
            <PreorderQuantity>0.0000</PreorderQuantity>
            <BackorderQuantity>0.0000</BackorderQuantity>
            <InventoryStatus>0</InventoryStatus>
            <LineItemOrdering>2008-05-15T12:29:39.373</LineItemOrdering>
            <ConfigurationId />
            <ProviderId />
          </LineItem>
          <LineItem>
            <Created>2008-05-15T12:29:39.42</Created>
            <Modified>2008-05-15T12:29:39.42</Modified>
            <Discounts />
            <OrderFormId>141</OrderFormId>
            <OrderGroupId>131</OrderGroupId>
            <Catalog>Everything2</Catalog>
            <CatalogNode>Everything</CatalogNode>
            <ParentCatalogEntryId />
            <CatalogEntryId>thecode</CatalogEntryId>
            <Quantity>2.0000</Quantity>
            <MinQuantity>1.0000</MinQuantity>
            <MaxQuantity>100.0000</MaxQuantity>
            <PlacedPrice>0.0000</PlacedPrice>
            <ListPrice>100.0000</ListPrice>
            <LineItemDiscountAmount>0.0000</LineItemDiscountAmount>
            <OrderLevelDiscountAmount>0.0000</OrderLevelDiscountAmount>
            <ShippingAddressId>Home</ShippingAddressId>
            <ShippingMethodName>Online Download</ShippingMethodName>
            <ShippingMethodId>17995798-a2cc-43ad-81e8-bb932f6827e4</ShippingMethodId>
            <ExtendedPrice>200.0000</ExtendedPrice>
            <Description />
            <Status />
            <DisplayName>Samsung LN52A650 52-inch 1080p 120Hz LCD HDTV with RED Touch of Color</DisplayName>
            <AllowBackordersAndPreorders>false</AllowBackordersAndPreorders>
            <InStockQuantity>0.0000</InStockQuantity>
            <PreorderQuantity>0.0000</PreorderQuantity>
            <BackorderQuantity>0.0000</BackorderQuantity>
            <InventoryStatus>0</InventoryStatus>
            <LineItemOrdering>2008-05-15T12:29:39.42</LineItemOrdering>
            <ConfigurationId />
            <ProviderId />
          </LineItem>
          <LineItem>
            <Created>2008-05-15T12:29:39.467</Created>
            <Modified>2008-05-15T12:29:39.467</Modified>
            <Discounts />
            <OrderFormId>141</OrderFormId>
            <OrderGroupId>131</OrderGroupId>
            <Catalog>Everything2</Catalog>
            <CatalogNode>Everything</CatalogNode>
            <ParentCatalogEntryId />
            <CatalogEntryId>thecode</CatalogEntryId>
            <Quantity>2.0000</Quantity>
            <MinQuantity>1.0000</MinQuantity>
            <MaxQuantity>100.0000</MaxQuantity>
            <PlacedPrice>0.0000</PlacedPrice>
            <ListPrice>100.0000</ListPrice>
            <LineItemDiscountAmount>0.0000</LineItemDiscountAmount>
            <OrderLevelDiscountAmount>0.0000</OrderLevelDiscountAmount>
            <ShippingAddressId>Home</ShippingAddressId>
            <ShippingMethodName>Online Download</ShippingMethodName>
            <ShippingMethodId>17995798-a2cc-43ad-81e8-bb932f6827e4</ShippingMethodId>
            <ExtendedPrice>200.0000</ExtendedPrice>
            <Description />
            <Status />
            <DisplayName>Samsung LN52A650 52-inch 1080p 120Hz LCD HDTV with RED Touch of Color</DisplayName>
            <AllowBackordersAndPreorders>false</AllowBackordersAndPreorders>
            <InStockQuantity>0.0000</InStockQuantity>
            <PreorderQuantity>0.0000</PreorderQuantity>
            <BackorderQuantity>0.0000</BackorderQuantity>
            <InventoryStatus>0</InventoryStatus>
            <LineItemOrdering>2008-05-15T12:29:39.467</LineItemOrdering>
            <ConfigurationId />
            <ProviderId />
          </LineItem>
        </LineItems>
        <Discounts />
        <Name>default</Name>
        <BillingAddressId>Home</BillingAddressId>
        <ShippingTotal>10.0000</ShippingTotal>
        <HandlingTotal>0.0000</HandlingTotal>
        <TaxTotal>0.0000</TaxTotal>
        <DiscountAmount>0.0000</DiscountAmount>
        <SubTotal>600.0000</SubTotal>
        <Total>610.0000</Total>
        <Status />
        <ProviderId />
      </OrderForm>
    </OrderForms>
    <OrderAddresses>
      <OrderAddress>
        <Created>2008-05-15T12:29:39.013</Created>
        <Modified>2008-05-15T12:29:39.013</Modified>
        <OrderGroupId>131</OrderGroupId>
        <Name>Home</Name>
        <FirstName />
        <LastName />
        <Organization>Company</Organization>
        <Line1 />
        <Line2 />
        <City />
        <State />
        <CountryCode />
        <CountryName />
        <PostalCode />
        <RegionCode />
        <RegionName />
        <DaytimePhoneNumber />
        <EveningPhoneNumber />
        <FaxNumber />
        <Email>who@someone.com</Email>
      </OrderAddress>
    </OrderAddresses>
    <InstanceId>a74023d4-4abd-4615-8d5e-51c766c158c4</InstanceId>
    <ApplicationId>e1dff5b7-8ec1-4f14-91a1-357c1bb968a0</ApplicationId>
    <AffiliateId>00000000-0000-0000-0000-000000000000</AffiliateId>
    <Name>Default</Name>
    <CustomerId>bf6da67a-8917-4173-ac96-7776efdb77e1</CustomerId>
    <CustomerName>John Doe</CustomerName>
    <AddressId />
    <ShippingTotal>10.0000</ShippingTotal>
    <HandlingTotal>0.0000</HandlingTotal>
    <TaxTotal>0.0000</TaxTotal>
    <SubTotal>600.0000</SubTotal>
    <Total>610.0000</Total>
    <BillingCurrency>USD</BillingCurrency>
    <Status>NewOrder</Status>
    <ProviderId />
    <TrackingNumber>PO131336</TrackingNumber>
    <ExpirationDate>9999-12-31T23:59:59.9999999</ExpirationDate>
  </PurchaseOrder>
</ContextDoc>
<OrderForms>

It is then processed by the template similar to this example.

Example: template processing

XML
<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" />
    <xsl:include href="order-shared.xsl"/>

    <xsl:template match="/">
        <html>
            <head id="Head1">
                <style type="text/css">
                    #PurchaseOrder {}
                    h1 {font-size: 20px;}
                    h2 {font-size: 18px;}
                    h3 {font-size: 16px; background-color: #cccccc; padding: 2px 2px 2px 2px}
                    .introduction {padding: 5px 0 0 0}
                    .footer {padding: 5px 0 0 0}
                </style>
                <title>
                    Order Notification
                </title>
            </head>
            <body>
                <xsl:apply-templates select="//PurchaseOrder"></xsl:apply-templates>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="PurchaseOrder">
        <div id="PurchaseOrder">
            <h1>Sale/Order Notification from the Mediachase Store</h1>

            <h1>**ORDER SUMMARY</h1>
            <xsl:call-template name="OrderHeader"></xsl:call-template>
            <div class="OrderForms">
                <h2>Products Purchased:</h2>
                <xsl:apply-templates select="OrderForms/OrderForm"></xsl:apply-templates>
            </div>

            <xsl:call-template name="OrderFooter"></xsl:call-template>

            <div class="Footer">
                Regards,<br/> Mediachase Software.
            </div>
        </div>
    </xsl:template>
</xsl:stylesheet>

Example: Order-shared.xsl

XML
<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" />

    <xsl:template name="OrderHeader">
        Order Number: <xsl:value-of select="TrackingNumber"/><br/>
        Status: <xsl:value-of select="Status"/><br/>
        Name: <xsl:value-of select="CustomerName"/><br/>
        Email: <a>
            <xsl:attribute name="href">
                mailto:<xsl:value-of select="//PurchaseOrder/OrderAddresses/OrderAddress[Name=//PurchaseOrder/OrderForms/OrderForm/BillingAddressId]/Email"/>
            </xsl:attribute>
            <xsl:value-of select="//PurchaseOrder/OrderAddresses/OrderAddress[Name=//PurchaseOrder/OrderForms/OrderForm/BillingAddressId]/Email"/>
        </a>
    </xsl:template>

    <xsl:template name="OrderFooter">
        <h3>Order Summary</h3>
        <div class="OrderSummary">
            Sub Total: <xsl:value-of select="BillingCurrency"/>&#160;<xsl:value-of select="format-number(SubTotal, '###,###.00')"/><br/>
            Handling Total: <xsl:value-of select="BillingCurrency"/>&#160;<xsl:value-of select="format-number(HandlingTotal, '###,###.00')"/><br/>
            Shipping Total: <xsl:value-of select="BillingCurrency"/>&#160;<xsl:value-of select="format-number(ShippingTotal, '###,###.00')"/><br/>
            Total Tax: <xsl:value-of select="BillingCurrency"/>&#160;<xsl:value-of select="format-number(TaxTotal, '###,###.00')"/><br/>
            TOTAL: <xsl:value-of select="BillingCurrency"/>&#160;<xsl:value-of select="format-number(Total, '###,###.00')"/><br/>
        </div>
    </xsl:template>

    <xsl:template match="OrderForm">
        <div class="OrderForm">
            <div class="OrderForms">
                <h3>Line Items</h3>
                <xsl:apply-templates select="LineItems/LineItem"></xsl:apply-templates>
                <h3>Payments</h3>
                <xsl:apply-templates select="Payments/Payment"></xsl:apply-templates>
            </div>
            <div class="OrderSummary">
                <!--
                Sub Total: <xsl:value-of select="SubTotal"/><br/>
                Handling Total: <xsl:value-of select="HandlingTotal"/><br/>
                Shipping Total: <xsl:value-of select="ShippingTotal"/><br/>
                Total Tax: <xsl:value-of select="TaxTotal"/><br/>
                Discount: <xsl:value-of select="DiscoutnAmount"/><br/>
                TOTAL: <xsl:value-of select="Total"/><br/>
                -->
            </div>
        </div>
    </xsl:template>

    <xsl:template match="LineItem">
        <div class="LineItem">
            <xsl:value-of select="format-number(Quantity, '###,###.##')"/>&#160;<xsl:value-of select="DisplayName"/> - <xsl:value-of select="//PurchaseOrder/BillingCurrency"/>&#160;<xsl:value-of select="format-number(ListPrice, '###,###.00')"/> each
        </div>
    </xsl:template>

    <xsl:template match="Payment">
        <div class="Payment">
            Payment Method: <xsl:value-of select="PaymentMethodName"/><br/>
            Amount: <xsl:value-of select="//PurchaseOrder/BillingCurrency"/>&#160;<xsl:value-of select="format-number(Amount, '###,###.00')"/>
        </div>
    </xsl:template>

</xsl:stylesheet>

Template engine

Calling the template engine API is done as in the example below.

Example: calling the template engine

C#
// Execute template processor
    string body = TemplateService.Process("order-confirm", Thread.CurrentThread.CurrentCulture, 
    new Dictionary<string, object>());

As you can see, three parameters are passed: template name, current culture and a dictionary collection.

Example: sending an order notification

C#
using System;
using System.Text;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MetaDataTest.Common;
using Mediachase.Commerce.Orders;
using Mediachase.MetaDataPlus;
using Mediachase.Commerce.Engine.Template;
using System.Threading;
using System.Net.Mail;

namespace UnitTests.OrderSystem
    /// <summary>
    /// Test class for different notifications related to order system.
    /// </summary>
    [TestClass]
    public class OrderSystem_Notifications
    {

        public OrderSystem_Notifications()
        {
        }

        [TestMethod]
        public void Notifications_CreditCard_CustomerEmail()
        {
            Cart cart = OrderHelper.CreateCartSimple(Guid.NewGuid());
            cart.OrderForms[0].Payments.Clear();
            cart.OrderForms[0].Payments.Add(OrderHelper.CreateCreditCardPayment());
            cart.AcceptChanges();
            cart.RunWorkflow("CartValidate");
            cart.RunWorkflow("CartPrepare");
            cart.RunWorkflow("CartCheckout");
            cart.AcceptChanges();
            PurchaseOrder po = cart.SaveAsPurchaseOrder();

            po = OrderContext.Current.GetPurchaseOrder(po.CustomerId, po.OrderGroupId);

            // Send emails
            SendEmail(po, "order-confirm");
            SendEmail(po, "order-notify");

            // Validate
            Assert.AreEqual(po.OrderForms[0].Payments.Count, 1);
        }

        private void SendEmail(PurchaseOrder order, string template)
        {
            // Add input parameter
            Dictionary<string, object> dic = new Dictionary<string, object>();
            dic.Add("OrderGroup", order);

            // Execute template processor
            string body = TemplateService.Process(template, Thread.CurrentThread.CurrentCulture, dic);

            // Send out emails
            MailMessage msg = new MailMessage();
            msg.From = new MailAddress("store@yourcompany.com", "UNIT TEST: Store");
            msg.To.Add(new MailAddress(order.OrderAddresses[0].Email, "UNIT TEST: " + order.Name));
            msg.Subject = "UNIT TEST: Store: Order Notification";
            msg.Body = body;
            msg.IsBodyHtml = true;

            SmtpClient client = new SmtpClient();
            client.Send(msg);
        }
    }
}

See also

 


Do you have feedback on this documentation? Send an email to documentation@episerver.com. For development-related questions and discussions, refer to our Forums on https://world.episerver.com/forum/