You are here: Architecture > E-mail and Notification Capabilities

E-mail and Notification Capabilities

Introduction

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

The template engine itself is very customizable and is based on the Provider Model. That means that the implementation we provide with a product can be easily customized or even completely replaced without the need to access any of the framework source code.

The default implementation we provide is XSL based template provider. It allows creating templates using XML Stylesheet Language(XSL). This provides a very powerful and flexible way of creating notification templates for different outgoing e-mails.

Key Classes and Files

TemplateService.cs - Loads the appropriate template provider and returns formatted text for 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

In the web.config file of your public/admin sites, look to this section:

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

You can add username and password in there as well if your SMTP server requires authentication. For more information about configuring the mail settings, see http://msdn.microsoft.com/en-us/library/w355a94k.aspx.

This section refers to the section regarding e-mail notifications.

<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 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

Please place the the PublicLayer\Templates\en-us items in the directory in template source. These are the template e-mails you need to change to meet your needs.

How it works

An example of calling the TemplateService can be found in the CheckoutWizardModule control. Relevent 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.

Code Example for Sending Out e-mails

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 frontend but can be applied to the commerce manager as well.

The template service replaces the placeholders with the proper text. You can add your own files to be used with the template service as well.

XSL/XML Template Provider

This 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 can't find file in the language specific folder it will try to fall back and look in the "default" folder.

For example when PurchaseOrder is passed to the provider the following XML is generated:

<?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:

<?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>


Order-shared.xsl:

<?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>

 

API

Calling the template engine is a pretty simple under taking and can be done with a few lines of code.

The code below demonstrates the simple call to the template engine.

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

 

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

More complete example on how to actually send an order notification is shown below:

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);
        }
    }
}

Namespaces

EPiServer.Business.Commerce.Sample - Contains CheckoutWizardModule

Mediachase.Commerce.Engine.Template.Providers - Contains XslTemplateProvider

Mediachase.Commerce.Engine.Template - Contains TemplateService and TemplateProvider

Mediachase.SampleSite.Templates.Everything.BusinessControls.CheckoutControls - Contains CheckoutWizardModule

Mediachase.SampleSite.Templates.Everything.BusinessControls.SelfServiceControls - Contains RecoverPasswordModule

 


Version: EPiServer Commerce 1 R2 SP2| Last updated: 2012-06-29 | Copyright © EPiServer AB | Send feedback to us