Hacking Sitecore and Life one pipeline at a time!

Creating A Custom Email Template: Part 2


Creating a Custom Email Template

Our second mini-series in 25 Days of Sitecore EXM continues today. Creating a Custom Email Template which is intended for more of a technical Sitecore audience. We build upon the branch structure started yesterday and showcase the presentation on emails.

Audience Assumptions

This blog series makes the following assumptions about the audience reading it. In order to get the most out of this blog post, having technical experience in Sitecore is required. This blog post is going to cover concepts specific to EXM, but is not going to explain fundamental Sitecore operations fully. Additionally, this blog series is going to assume that HTML/CSS for emails are already created and associated Layouts, Sublayouts, and Renderings are already created.

Adding Presentation

Following from yesterday’s post, now that our Message Root is created, we are ready to add presentation. This is actually the easiest part of the message creation for EXM because for developers this is no different than creating the presentation for any other part of the website. We create a layout and then add some renderings that have data sources. The only real difference is that all of the data sources are child items of the page item, which is, in this case, the Message Root item.

Select the Layout

Assuming that you have already created some HTML/CSS for your email, we’ll need to integrate that HTML into a Layout view. For our Example, we’re going to create a Layout Called “Branded Email Layout” and referencing the EmailMainLayout.cshtml.

_EmailBaseLayout.cshtml


@using Sitecore.ExperienceForms.Mvc.Html
@using Sitecore.Mvc.Analytics.Extensions
@using SitecoreHacker.Sample.Feature.Email;


@model RenderingModel
@{
    var repository = new EmailOptionsRepository();
    var options = repository.Get(Model.Item);
}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    @RenderSection("head", false)
</head>
<body style="font-family: Georgia, Times, Times New Roman, serif; background-color: black;">
    <!-- START LIQUID WRAPPER -->
    <!--[if mso]>
        <table cellpadding="0" cellspacing="0" border="0" style="padding:0px;margin:0px;width:100%;">
        <tr><td colspan="3" style="padding:0px;margin:0px;font-size:20px;height:20px;" height="20">&nbsp;</td></tr>
        <tr>
        <td style="padding:0px;margin:0px;">&nbsp;</td>
        <td style="padding:0px;margin:0px;" width="832">
    <![endif]-->
    <div style="max-width: 832px; margin: auto;">
        @Html.Raw(options.BeforeBodyHtml)
        @RenderBody()
        @Html.Raw(options.AfterBodyHtml)
    </div>
    <!--[if mso]>
        </td>
        <td style="padding:0px;margin:0px;">&nbsp;</td>
        </tr>
        <tr><td colspan="3" style="padding:0px;margin:0px;font-size:20px;height:20px;" height="20">&nbsp;</td></tr>
        </table>
    <![endif]-->
    <!-- END LIQUID WRAPPER -->
</body>
</html>

EmailMainLayout.cshtml

@using Sitecore.Mvc.Analytics.Extensions
@using SitecoreHacker.Sample.Feature.Email
@{
    Layout = "_EmailBaseLayout.cshtml";
}
@model RenderingModel
@{
    var repository = new EmailOptionsRepository();
    var options = repository.Get(Model.Item);
}
@section head
{
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@Html.Sitecore().Field("Page Title", new { DisableWebEdit = true })</title>
    @Html.Sitecore().Placeholder("newsletter_head")
    <style type="text/css">
        #outlook a {
            padding: 0;
        }

        body {
            width: 100% !important;
            -webkit-text-size-adjust: 100%;
            -ms-text-size-adjust: 100%;
            margin: 0;
            padding: 0;
        }

        #backgroundTable {
            margin: 0;
            padding: 0;
            width: 100% !important;
            line-height: 100% !important;
        }

        table td {
            border-collapse: collapse;
        }
    </style>
}
<table cellpadding="0" cellspacing="0" border="0" id="backgroundTable" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt;">
    <tr>
        <td>
            <table cellpadding="0" cellspacing="0" width="832" border="0" align="center" style="border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt;">
                <tr>
                    <td colspan="3" align="center">
                        <br /><br />
                    </td>
                </tr>
                <tr>
                    <td colspan="3" align="center">
                        @Html.Sitecore().Placeholder("top-image")
                    </td>
                </tr>
                <tr>
                    <td colspan="3" bgcolor="#f7f2e7" align="center">
                        <br /> @Html.Sitecore().Placeholder("email-logo")<br /><br />
                    </td>
                </tr>
                <tr>
                    <td width="8%" valign="top" bgcolor="#f7f2e7"></td>
                    <td width="84%" valign="top" bgcolor="#f7f2e7" style="line-height: 1.4; font-size: 16px;">
                        @Html.Sitecore().Placeholder("primary-content")
                    </td>
                    <td width="8%" valign="top" bgcolor="#f7f2e7"></td>
                </tr>
                <tr>
                    <td colspan="3" align="center">
                        @Html.Sitecore().Placeholder("bottom-image")
                    </td>
                </tr>
                <tr>
                    <td colspan="3" align="center">
                        <br /><br />@Html.Sitecore().Placeholder("footer-logo")<br /><br />
                    </td>
                </tr>
            </table>
        </td>
    </tr>
</table>

Note the use of placeholders in this view. These placeholders are where renderings will be added to the presentation.

Email Options Repository

@model RenderingModel
@{
    var repository = new EmailOptionsRepository();
    var options = repository.Get(Model.Item);
}

Oh you noticed that Email Options Repository, eh? If you recall from the Sample Newsletter, there’s an Options item under the Message Root.

This Options item has a number of fields that can be useful for content authors to have some more control over the look and feel of their emails without changing the overall code of the email or requiring a developer.

To reuse this item, you’ll want to create an EmailOptionsRepository() class in your solution. Here’s the code for that.

using System;
using System.Linq;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.EmailCampaign.SampleNewsletter;
using Sitecore.EmailCampaign.SampleNewsletter.Extensions;
using Sitecore.EmailCampaign.SampleNewsletter.Models;
using Sitecore.EmailCampaign.SampleNewsletter.Services;

namespace SitecoreHacker.Sample.Feature.Email
{
    public class EmailOptionsRepository
    {
        private const int DefaultMaxWidth = 800;
        private readonly FindNewsletterRootService _findNewsletterRootService;

        public EmailOptionsRepository()
            : this(new FindNewsletterRootService())
        {
        }

        public EmailOptionsRepository(FindNewsletterRootService findNewsletterRootService)
        {
            Assert.ArgumentNotNull(findNewsletterRootService, "findNewsletterRootService");
            _findNewsletterRootService = findNewsletterRootService;
        }

        public NewsletterOptions Get(Item contextItem)
        {
            Assert.ArgumentNotNull(contextItem, "contextItem");
            var newsletterRoot = _findNewsletterRootService.FindNewsletterRoot(contextItem);
            var obj = newsletterRoot.Children.FirstOrDefault(c =>
                c.IsDerived(Templates.NewsletterOptions.ID));
            if (obj == null)
                throw new ArgumentException($"Cannot find EmailOptionsRepository below '{newsletterRoot.Paths.FullPath}'");
            if (!int.TryParse(obj[Templates.NewsletterOptions.Fields.MaxWidth], out var result))
                result = 800;
            return new NewsletterOptions
            {
                ContentFontSize = obj[Templates.NewsletterOptions.Fields.ContentFontSize],
                FontFamily = obj[Templates.NewsletterOptions.Fields.FontFamily],
                HeadingFontSize = obj[Templates.NewsletterOptions.Fields.HeadingFontSize],
                MaxWidth = result,
                BeforeBodyHtml = obj[Templates.NewsletterOptions.Fields.BeforeBodyHtml],
                AfterBodyHtml = obj[Templates.NewsletterOptions.Fields.AfterBodyHtml]
            };
        }
    }
}

Complete the Rest of the Presentation

From this point forward, adding Presentation to the Message Root item is standard practice, and there isn’t anything specific to EXM that would need clarification. As the point of this blog series is to showcase EXM, feel free to create your template any way you like, making use of any of the features of Sitecore. Here’s our example presentation properties.

In our example above, I created two components Email Content and Email Image. These components are exposed through the specified placeholder settings items.

That’s it!  We have now created a Sitecore Email Experience Manager branch message template.


This completes Part 2 of Creating a Custom Email Template and finished out Day 10!  Tomorrow we’ll finish this mini-series by activating our new branch template and assigning it to our EXM Manager Root.


Don’t forget to register for my Sitecore EXM webinar on December 13 EXM Live! An Email Automation Experience!

Register for EXM Live! Webinar


To register for this webinar, visit https://dx.connectivedx.com/2018-exm-webinar

Tagged as: ,

Categorised in: EXM, Sitecore

1 Response »

Trackbacks

  1. 25 Days of Sitecore EXM | Sitecore Hacker

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Enter your email address to follow this blog and receive notifications of new posts by email.

Join 1,238 other subscribers

Blog Stats

  • 132,847 hits
Follow Sitecore Hacker on WordPress.com
Sitecore® and Own the Experience® are registered trademarks of Sitecore Corporation A/S in the U.S. and other countries.  This website is independent of Sitecore Corporation, and is not affiliated with or sponsored by Sitecore Corporation.
%d bloggers like this: