Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where to store email templates

I have an asp.net web application, which sends several emails to users during the signup procedure. Right now I have them inline with the code, but I would like to hold them in a central location where I can edit them without going in to VS.

What would be the best place/format to store these HTML templates?

like image 490
Elad Lachmi Avatar asked Jul 24 '11 15:07

Elad Lachmi


1 Answers

I store all my e-mail templates for my web-app as ASP.NET MVC Razor Views, but as embedded resource in a light assembly that I can easily reference from any project.

A template looks like this (notice the localization):

@model Milkshake.Commerce.Model.Users.UserDto
@using Milkshake.Core.Internationalization;
@using Milkshake.Commerce.Model.Meta;

@if (Language.CurrentForInterface.TwoLetterISOLanguageName.Equals("da"))
{

<h1>Hej @Model.FirstName</h1>

<p>
    Din nye brugerkonto til Milkshake Commerce er blevet oprettet.
</p>

<p>
    Gå til dine <a href="http://@ShopSettings.Instance.Domain.TrimEnd('/')/Account">konto indstillinger</a>, brug din e-mail adresse som adgangskode og du vil blive videreført til dine konto indstillinger, hvor du kan ændre din adgangskode.
</p>

<p>Ha' en god dag!</p>
<h2>The Milkshake Commerce Team!</h2>

}
else
{

<h1>Hi @Model.FirstName</h1>

<p>
    Your new user account for Milkshake Commerce has been created for you.
</p>

<p>
    Go to your <a href="http://@ShopSettings.Instance.Domain.TrimEnd('/')/Account">user account page</a>, use your e-mail address as password and you'll be taken directly to your account page where you can change your password.
</p>

<p>Have a nice day!</p>
<h2>The Milkshake Commerce Team!</h2>

}

Then I have a "master" template, called _AppEmailTemplate.cshtml:

@using Milkshake.Commerce.Model.Resources

<!DOCTYPE html PUBLIC -//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd>

<html xmlns="http://www.w3.org/1999/xhtml">

    <head>
        <title></title>

        <style type="text/css">
            body
            {
                font-family: Arial, Helvetica;
            }
            .layout-wrapper
            {
                width: 600px;
            }
            .header
            {
                background-color: #242225;
            }
            .header img
            {
                display: block;
            }
            .content
            {
                background-color: #ffffff; padding: 10px 20px; border: 10px solid #eaeaea; border-top: none;
            }
            .footer
            {
                padding: 20px; padding-top: 5px; font-size: 10px; color: #cccccc;
            }
            p
            {
                font-size: 14px;
            }
            p.company-details
            {
                font-size: 12px;
            }
            h1
            {
                font-size: 20px;
            }
            h2
            {
                font-size: 16px;
            }
        </style>
        <style type="text/css" id="mobile">
            @@media only screen and (max-device-width: 480px) {
                body
                {
                }
                .layout-wrapper
                {
                    width: 480px !important;
                }
                .header
                {
                    background-color: transparent !important;
                }
                .header img
                {
                    width: 480px !important;
                }
                .content
                {
                    border: none !important;
                }
                .footer
                {
                    padding-top: 15px !important;
                }
                p
                {
                    font-size: 22px !important;
                }
                h1
                {
                    font-size: 28px !important;
                }
                h2
                {
                    font-size: 24px !important;
                }
            }
        </style>
    </head>

    <body leftmargin="0" marginwidth="0" topmargin="0" marginheight="0" offset="0" bgcolor="#f1f1f1">

        <table width="100%" cellpadding="0" cellspacing="0" bgcolor="#f1f1f1">
            <tr>
                <td valign="top" align="center">

                    <table cellpadding="0" cellspacing="0" width="100%" height="80">
                        <tr>
                            <td class="header" align="center">
                                <table cellpadding="0" cellspacing="0" width="600" height="80" class="layout-wrapper" style="width: 600px;">
                                    <tr>
                                        <td>
                                            <img src="http://example.com/email-header.png" alt="Milkshake Commerce" />
                                        </td>
                                    </tr>
                                </table>
                            </td>
                        </tr>
                    </table>

                    <table cellpadding="0" cellspacing="0" width="600" class="layout-wrapper">
                        <tr>
                            <td class="content" align="left">
                                #¤#¤CONTENTSECTION#¤#¤
                            </td>
                        </tr>
                        <tr>
                            <td class="footer" align="left">
                                <p>@Text.appEmailDisclaimer</p>
                                <p>@Text.appEmailFooterAd.UrlDecode()</p>
                                <p class="company-details"><i>Company name etc.</i></p>
                            </td>
                        </tr>
                    </table>

                </td>
            </tr>
        </table>

    </body>

</html>

To actually send the e-mail, I use RazorEngine for rendering:

public void SendSystemEmail<T>(string templateName, string subject, string fromName, string recipientEmail, T model)
{
    dynamic template = this.GetEmailTemplate(templateName);
    string layoutBody = RazorEngine.Razor.Parse(template.Layout as string, model);
    string emailBody = RazorEngine.Razor.Parse(template.Template as string, model);

    emailBody = layoutBody.Replace(CONTENTSECTIONREPLACETOKEN, emailBody);

    PreMailer.Net.PreMailer pm = new PreMailer.Net.PreMailer();
    emailBody = pm.MoveCssInline(emailBody, true);

    EmailDto email = new EmailDto();
    email.Body = emailBody;
    email.IsBodyHtml = true;
    email.FromEmail = "[email protected]";
    email.ReplyToEmail = email.FromEmail;
    email.FromName = fromName;
    email.RecipientEmail = recipientEmail;
    email.Subject = subject;
    email.Type = EmailTypes.Transactional;

    if (String.IsNullOrWhiteSpace(email.FromName))
    {
        email.FromName = "Milkshake Software";
    }

    this.SendMailMessages(new List<EmailDto>() { email }, false);
}

The above code uses my own EmailDto object. Here you can easily create a [MailMessage][2] instance directly, and send it using the [SmtpClient][3].

Also, to get the best rendering in all e-mail clients, I use my own PreMailer.Net library to move all CSS inline. Read my blog post here, for more information. (Code is on Github)

The GetEmailTemplate does this:

/// <summary>
/// Gets the email template.
/// </summary>
/// <param name="templateName">Name of the template.</param>
/// <returns>Returns the e-mail template.</returns>
private dynamic GetEmailTemplate(string templateName)
{
    string masterTemplateContents = this.GetTemplateFileContents("_AppEmailTemplate.cshtml");
    string templateContents = this.GetTemplateFileContents(templateName + ".html.cshtml");

    return new { Layout = masterTemplateContents, Template = templateContents };
}

/// <summary>
/// Gets the template file contents.
/// </summary>
/// <param name="templateFileName">The name of the template file.</param>
/// <returns>Returns the contents of the template file.</returns>
private string GetTemplateFileContents(string templateFileName)
{
    return this.GetEmailFileContents("Templates", templateFileName);
}

/// <summary>
/// Gets the email file contents.
/// </summary>
/// <param name="lastNamespaceToken">The last namespace token.</param>
/// <param name="templateFileName">The name of the template file.</param>
/// <returns>
/// Returns the contents of the template file.
/// </returns>
private string GetEmailFileContents(string lastNamespaceToken, string templateFileName)
{
    var assembly = Assembly.GetExecutingAssembly();

    if (assembly != null)
    {
        StringBuilder sb = new StringBuilder();

        using (StreamReader sr = new StreamReader(assembly.GetManifestResourceStream(String.Format("MyApp.BusinessLogic.Communication.{0}.{1}", lastNamespaceToken, templateFileName))))
        {
            while (!sr.EndOfStream)
            {
                var line = sr.ReadLine();

                if (!line.StartsWith("@model"))
                {
                    sb.AppendLine(line);
                }
            }
        }

        return sb.ToString();
    }

    return null;
}
like image 128
MartinHN Avatar answered Oct 06 '22 00:10

MartinHN