Adding External Content to EXM email

In my two previous posts, How to send an EXM email from code and How to use custom tokens in EXM while sending emails from code?, I discussed how to add custom/external data to EXM messages. The solution is good when you only have a few tokens to replace. What if the goal is to add more personalized information, for instance, customer’s wishlist or related product list?

An EXM message is no different than a regular Sitecore page, i.e. it uses layouts, sublayouts/rendering for presentation. With that in mind, I built a custom EXM template and a custom rendering that fills in the data. Here is a screenshot of my email template and the resulting email.

Email Template

Email that was sent

How to set it up

  • Step 1: Create a new message template. You can follow these instructions. This is how your message template should look:
  • Step 2: Create a new sublayout/rendering. I am going to use a sublayout, as Sitecore’s default message templates use the WebForm layouts. This will make it easy for me to reuse some of Sitecore’s existing renderings.

    Here is the code I used.

    <asp:Panel runat="server" ID="pnlPlaceholderText">
        <h3>This will be replaced with product list</h3>
    <asp:Panel runat="server" ID="pnlListView" Visible="False">
        <asp:ListView runat="server" ID="lvProductList" OnItemDataBound="lvProductList_OnItemDataBound">
                    <asp:PlaceHolder runat="server" ID="itemPlaceHolder"></asp:PlaceHolder>
                    <asp:Literal runat="server" ID="litText"></asp:Literal>
    private readonly ILogger logger;
            private readonly AnalyticsGateway _gateway;
            private readonly IContactDataRepository _contactDataRepository;
            public ExternalDataExample(IContactDataRepository contactDataRepository)
                _contactDataRepository = contactDataRepository;
                logger = Logger.Instance;
                _gateway = EcmFactory.GetDefaultFactory().Gateways.AnalyticsGateway;
            private void Page_Load(object sender, EventArgs e)
                if (!Sitecore.Context.PageMode.IsNormal)
                    var contactIdQueryKey = GlobalSettings.AnalyticsContactIdQueryKey;
                    var contactIdString = WebUtil.GetQueryString(contactIdQueryKey);
                    ShortID contactId;
                    if (string.IsNullOrEmpty(contactIdString) || !ShortID.TryParse(contactIdString, out contactId))
                    var contact = _gateway.GetReadonlyContact(contactId.Guid);
                    if (contact == null) return;
                    // use the custom facet to retrieve data from external sources, for instance _externalDataSourceManager.GetData("use the identifier")
                   lvProductList.DataSource = _repository.GetProductListForContact(contact);
                    pnlPlaceholderText.Visible = false;
                    pnlListView.Visible = true;
                catch (Exception ex)
                    pnlPlaceholderText.Visible = pnlListView.Visible = false;
                    logger.LogError("could not render product list", ex);
       protected void lvProductList_OnItemDataBound(object sender, ListViewItemEventArgs e)
                if (e.Item.ItemType == ListViewItemType.DataItem)
                    // Display the e-mail address in italics.
                    var litText = (Literal)e.Item.FindControl("litText");
                    litText.Text = e.Item.DataItem.ToString();
  • Step 3: Attach the rendering to your message layout
  • Step 4: Create a new email message using the new template.

You should now be able to use it to fetch content from external systems and add it to your email messages.

You can find the complete code here. Note that in my code I am using a custom facet, you can read more about it in my post Extending xDB – Custom Contact Facets


Adding External Content to EXM email
Tagged on:     

Leave a Reply

Your email address will not be published. Required fields are marked *