Where to store email templates
I would recommend storing the e-mail templates in an XML file which will allow scalability in the future by adding attributes to the mail template and it will also allow easy edit.
Hope you were sorted, this is what I found and thought was easier.
- Open properties of your project.
- Go to the resource. Under resource 'Add Resource' => 'Add Existing File'
Then you can just access it like this.
var html = Resources.YourFileName;
Remember to add using
using YourProject.Properties;
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;
}