Category Archives: HTML

Formatting email HTML with T4 templates

There’s several techniques available to a .Net developer to properly format HTML outside web pages. One of them is actually using an HTML view render engine like Razor to format it.

The one I find the cleaner and easier to maintain is using T4 templates. Since this is a post about T4, I suggest that you take a loot at my T4 Templates page before moving on, to get used to the code reading.

The full demo project can be downloaded here

Project Structure

blog17

The simple demo project is composed of two T4 Runtime Templates:

  • EmailTemplate defines and transforms the default HTML template.
  • The BodyTemplate defines and transforms the HTML that composes the “Body” of the email.

The entry point for this template transformation is on the MailExtensions.cs file and written as extensions to MailMessage. The Program.cs file just contains enough code to setup an email message and call the template entry point

class Program
{
    static void Main(string[] args)
    {
        var mail = new MailMessage
        {
            From = new MailAddress("me@mycompany.com", "Me AndMe"),
            Subject = "Me poking You",
            Body = string.Empty
        };

        mail.To.Add("someemail@somecompany.com");

        var template = new BodyTemplate
                            {
                                FirstName = "You",
                                LastName = "AndYou"
                            };

        mail.CreateHtmlBody(template);

        using (var client = new SmtpClient())
        {
            client.SendAsync(mail, null);
        }
    }
}

The email is just setup to be delivered to a static folder in the app.config file

<system.net>
    <mailSettings>
        <smtp deliveryMethod="SpecifiedPickupDirectory">
            <specifiedPickupDirectory pickupDirectoryLocation="D:\Mail" />
        </smtp>
    </mailSettings>
</system.net>

T4 Runtime Templates

To create a T4 Runtime Template all you have to do is Add New Item, then select the Runtime Text Template Item.

blog18

What this template does is generate a C# class that you can use at Run-Time to transform and generate it’s output. You can either pass parameters to these templates by using their built in T4 Parameter Directive or simply by extending the generated partial class. I prefer extending the generated class as it makes it more unit testable when required, so I used this approach in the demo code.

This type of templates ignores some of the T4 Directives, however some of them are put to good use to trick the editor into proper syntax highlighting. I use the T4 Output Directive to make tangible syntax highlight my HTML, for some reason at the time of this post, tangible didn’t highlight it with “.html” so “.xml” had to do the trick.

<#@ output extension=".xml" #>

The EmailTemplate

The template itself is very simple, containing very simple HTML. This should contain the default style template for your emails, with a proper Header, Footer and common sections in all your emails.

<#@ template language="C#" #>
<#@ output extension=".xml" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<html>
  <body>
    <h1>This is a header</h1>
    <div>
		<#= GetBodyText() #>
    </div>
    <h1>This is a footer</h1>
</body>
</html>

The generated class partial definition contains the method used by the template to generate the Body. This method supports both a Body string and a Body object that will be verified as being another valid template. So if it get’s another template it will attempt to render it, while if it get’s a string it will just dump it.

public partial class EmailTemplate
{
    public string Body { get; set; }

    private object _bodyTemplate;
    public object BodyTemplate
    {
        get { return _bodyTemplate; }
        set
        {
            // Get the type and the TransformText method using reflection
            var type = value.GetType();
            var method = type.GetMethod("TransformText");

            // Reflection signature checks
            if (method == null) throw new ArgumentException("BodyTemplate needs to be a RunTimeTemplate with a TransformText method");
            if (method.ReturnType != typeof(string) || method.GetParameters().Any()) throw new ArgumentException("Wrong TransformText signature on the BodyTemplate");

            // If everything is ok, assign the value
            _bodyTemplate = value;
        }
    }

    private string GetBodyText()
    {
        var result = string.Empty;

        // Use the BodyTemplate if available
        if(BodyTemplate != null)
        {
            dynamic castTemplate = BodyTemplate;
            result = castTemplate.TransformText();
        }
        // Otherwise use the Body string if it's not null or empty
        else if(!string.IsNullOrEmpty(Body))
        {
            result = Body;
        }

        return result;
    }
}

The BodyTemplate

The BodyTemplate is a very simple template just to show the linear transformation of both templates and the inclusion of email specific fields for email customization.

<#@ template language="C#" #>
<#@ output extension=".xml" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<p>Hi there <#= FirstName #> <#= LastName #></p>
<p>This is an Example of a Body.</p>

It’s extension only contains properties so that we can configure the email Body.

public partial class BodyTemplate
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

The Entry Point – MailExtensions

The wrapper methods that manage the main template transformations are in the MailExtensions.cs file and are written as extension methods, one for a using a Body string and another one for using a Body template. This demo however doesn’t make any use of the Body string, it only uses a Body template.

public static class MailExtensions
{
    public static void CreateHtmlBody(this MailMessage message, string body)
    {
        var mailTemplate = new EmailTemplate { Body = body };
        var html = AlternateView.CreateAlternateViewFromString(mailTemplate.TransformText(), Encoding.UTF8, "text/html");
        message.AlternateViews.Add(html);
    }

    public static void CreateHtmlBody(this MailMessage message, object template)
    {
        var mailTemplate = new EmailTemplate { BodyTemplate = template };
        var html = AlternateView.CreateAlternateViewFromString(mailTemplate.TransformText(), Encoding.UTF8, "text/html");
        message.AlternateViews.Add(html);
    }
}