In yesterday’s post I went into detail about the challenges in delivering email templates. This is an interesting problem and the internet doesn’t have a lot of content about how real companies handle these challenges. Most of the posts I found provided detail about how to create static emails or extremely simplistic dynamic emails using things like the deprecated HtmlTextWriter.

The .NET ecosystem has a few other solutions such as Postal. I’ve used this tool on personal projects before. It’s OK in a pinch, but it doesn’t help you with the serious challenge of making sure your formatting will be consistent across the most popular email clients. Have you ever attempted to build a responsive layout for Outlook 2013? Good luck.

Our previous solution used code generated by a graphical designer in Mandrill. These tools are ok for static marketing emails, but as soon as you need to conditionally display a section, things get messy. Need to get into the code 2 years later and make some changes? Maybe I’ll go to trade school and find a new profession. Here’s the end of one of our 1200 line Mandrill templates, and I promise you the rest of it isn’t any better:

...truncated for sanity
                                                                                            </td>
                                                                                          </tr>
                                                                                      </tbody>
                                                                                    </table>
                                                                                    <!--[if gte mso 6]>
                                                                                </td>
                                                                                <td align="left" valign="top">
                                                                                    <![endif]-->
                                                                                </td>
                                                                              </tr>
                                                                          </tbody>
                                                                        </table>
                                                                    </td>
                                                                  </tr>
                                                              </tbody>
                                                            </table>
                                                        </td>
                                                      </tr>
                                                  </tbody>
                                                </table>
                                            </td>
                                          </tr>
                                      </tbody>
                                    </table>
                                </td>
                              </tr>
                          </table>
                        </td>
                    </tr>
                  </table>
                  <!-- // END FOOTER -->
              </td>
            </tr>
        </table>
        <!-- // END TEMPLATE -->
      </td>
  </tr>
</table>

This is a list of requirements we had for a better solution:

  • High level abstraction for designing email templates
  • Ability to view template output as we build
  • Automatic inlining of CSS rules
  • Ability to reuse HTML components
  • Easy to maintain and update
  • Templating engine for backend processing - variables, loops, if statements

Foundation for Emails meets most of those requirements. The only requirement it doesn’t hit is the templating engine for backend processing. How were we going to conditionally display a section, iterate over a collection, or display variables? My initial thought was to just use String.Replace on the backend for dynamic bits, but that gets really complicated. A hyperlink in this email isn’t just a simple <a> tag. This is a sample of one of the compiled anchor tags:

<a
  href="https://velaro.com"
  style="Margin:0;color:#4c75ab;font-family:Helvetica,Arial,sans-serif;font-weight:400;line-height:1.3;margin:0;padding:0;text-align:left;text-decoration:none"
  >velaro.com</a
>

Now maybe we could just make the text or the src dynamic and replace those. That might work, but what about iterating over some data to display a table?

<tbody>
  <tr style="padding:0;text-align:left;vertical-align:top">
    <td
      style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border:1px solid #ccc;border-collapse:collapse!important;color:#0a0a0a;font-family:Helvetica,Arial,sans-serif;font-size:80%;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:5px;text-align:left;vertical-align:top;word-wrap:break-word"
    >
      Question
    </td>
    <td
      style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border:1px solid #ccc;border-collapse:collapse!important;color:#0a0a0a;font-family:Helvetica,Arial,sans-serif;font-size:80%;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:5px;text-align:left;vertical-align:top;word-wrap:break-word"
    >
      Answer
    </td>
  </tr>
</tbody>

String.Replace is looking like a terrible idea. If something seems like a terrible idea, it probably is, and this is no exception. Beyond that, we don’t want to look at this garbage in our lovely C# code. Maybe we could hide it in a #region? OK, that was a bad joke. No self-respecting programmer would ever do such a thing, right? Any updates we make to styling would have to be somehow copied over to the backend… Yuck.

We needed something better, a way to place our variables and other template syntax within our high level Foundation code. Unfortunately, the .NET ecosystem has very few good options for building HTML templates. Razor is the standard engine for building websites, but it has a mess of dependencies that make a bad option for simple text + data = html problems.

We settled for Handlebars.Net, it does everything we need but there’s one remaining problem. Foundation also uses Handlebars. How do we prevent it from attempting to render the variables too early?

<h3>
  <center>Agent Survey</center>
</h3>
<table class="survey-table">
  <thead>
    <tr>
      <th>Question</th>
      <th>Answer</th>
    </tr>
  </thead>
  <tbody>
    \{{#each Responses}}
    <tr>
      <td>\{{ Question }}</td>
      <td>\{{ Answer }}</td>
    </tr>
    \{{/each}}
  </tbody>
</table>

We use the escape character! A simple backslash preserves the handlebars block which can then be processed by our backend. Our build process places the HTML files in a specific backend directory which is flagged to include all files as embedded resources.

<ItemGroup>
  <None Remove="Mail\Templates\**\*.html" />
</ItemGroup>

<ItemGroup>
  <EmbeddedResource Include="Mail\Templates\**\*.html" />
</ItemGroup>

We then use a base class to load and render the templates

public abstract class MailTemplateBase<T>
{
    private readonly string _fileName;
    private static Func<object, string> _template;

    protected MailTemplateBase(string fileName)
    {
        _fileName = fileName;
    }

    public virtual string Render(T model)
    {
        var template = GetTemplate();
        return template(model);
    }

    private Func<object, string> GetTemplate()
    {
        if (_template != null)
        {
            return _template;
        }

        var source = GetSource();
        return _template = Handlebars.Compile(source);
    }

    private string GetSource()
    {
        var assembly = Assembly.GetExecutingAssembly();
        var resourceName = $"Velaro.Core.Mail.Templates.{_fileName}";
        using (Stream stream = assembly.GetManifestResourceStream(resourceName))
        using (StreamReader reader = new StreamReader(stream))
        {
            return reader.ReadToEnd();
        }
    }
}

This is an implementation of that base class. We want explicit models for each template because of the dynamic nature of these templates. If we render against domain classes and those domain classes change, we want our compiler to complain about it.

public class AgentSurveyTemplate : MailTemplateBase<AgentSurveyTemplateModel>
{
    public AgentSurveyTemplate() : base("agent-survey.html")
    {
    }
}

public class AgentSurveyTemplateModel
{
    public string AgentName { get; set; }
    public string EngagementId { get; set; }
    public string StartDate { get; set; }
    public IEnumerable<AgentSurveyTemplateResponse> Responses { get; set; } = new List<AgentSurveyTemplateResponse>();
}

public class AgentSurveyTemplateResponse
{
    public string Question { get; set; }
    public string Answer { get; set; }
}

And our unit tests look like this:

[Fact]
public void Render()
{
    var template = new AgentSurveyTemplate();

    var html = template.Render(new AgentSurveyTemplateModel
    {
        AgentName = "test-agent-name",
        EngagementId = "test-engagement-id",
        StartDate = "start-date",
        Responses = new List<AgentSurveyTemplateResponse>
        {
            new AgentSurveyTemplateResponse
            {
                Question = "question-1",
                Answer = "answer-1"
            },
            new AgentSurveyTemplateResponse
            {
                Question = "question-2",
                Answer = "answer-2"
            },
        }
    });

    Assert.Contains("test-agent-name", html);
    Assert.Contains("test-engagement-id", html);
    Assert.Contains("question-1", html);
    Assert.Contains("answer-1", html);
    Assert.Contains("question-2", html);
    Assert.Contains("answer-2", html);
    Assert.Contains("start-date", html);
}

The end result is clean and simple markup that we can fearlessly modify at any time with little effort:

---
subject: Agent Survey
---

<container>
  <center>{{> logo }}</center>
  <spacer size="16"></spacer>

  <h3>
    <center>Agent Survey</center>
  </h3>
  <table class="survey-table">
    <thead>
      <tr>
        <th>Question</th>
        <th>Answer</th>
      </tr>
    </thead>
    <tbody>
      \{{#each Responses}}
      <tr>
        <td>\{{ Question }}</td>
        <td>\{{ Answer }}</td>
      </tr>
      \{{/each}}
    </tbody>
  </table>
  <spacer size="30"></spacer>

  <h3>
    <center>Chat Information</center>
  </h3>
  <table  class="survey-table">
    <tbody>
      <tr>
        <td>Engagement Id</td>
        <td>\{{ EngagementId }}</td>
      </tr>
      <tr>
        <td>Agent</td>
        <td>\{{ AgentName }}</td>
      </tr>
      <tr>
        <td>Start Date</td>
        <td>\{{ StartDate }}</td>
      </tr>
    </tbody>
  </table>
  <spacer size="30"></spacer>

  {{> social }}
</container>

Overall I’m pretty happy with this solution. At first, I was resistant to the idea of having to escape blocks for server rendering, but it slowly turned into the least bad option. Having now updated a number of our emails, I can say I almost enjoy the escape characters. They’re a simple notation to let us know “this gets handled on the backend”. I never like including more NuGet or NPM dependencies into our project, but the alternative of writing our own templating engine is a far worse option and Foundation for Emails is mature and well done.

I’m now grabbing all of the previously avoided email tasks out of our backlog and knocking them off one by one. It feels good to be productive working on something that should be easy, like email templates.