存储电子邮件模板的位置

时间:2011-07-24 15:06:46

标签: .net asp.net email-templates

我有一个asp.net Web应用程序,它在注册过程中向用户发送几封电子邮件。现在我让它们与代码内联,但我想把它们放在一个中心位置,我可以在那里编辑它们而无需进入VS.

存储这些HTML模板的最佳位置/格式是什么?

6 个答案:

答案 0 :(得分:14)

我将我的网络应用程序的所有电子邮件模板存储为 ASP.NET MVC Razor Views ,但作为嵌入式资源存储在轻量级程序集中,我可以轻松来自任何项目的参考。

模板看起来像这样(注意本地化):

@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>

}

然后我有一个名为_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>

要实际发送电子邮件,我使用RazorEngine进行渲染:

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 = "support@example.com";
    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);
}

上面的代码使用我自己的EmailDto对象。您可以在此处直接轻松创建[MailMessage][2]实例,并使用[SmtpClient][3]发送。

此外,为了在所有电子邮件客户端中获得最佳呈现效果,我使用自己的PreMailer.Net库来内联所有CSS。有关详细信息,请阅读my blog post here。 (代码在Github上)

GetEmailTemplate执行此操作:

/// <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;
}

答案 1 :(得分:1)

我建议将电子邮件模板存储在XML文件中,以便将来通过向邮件模板添加属性来实现可扩展性,并且还可以轻松编辑。

答案 2 :(得分:1)

希望您被排序了,这是我发现的,并且认为更容易。

  1. 打开项目的属性。
  2. 转到资源。在资源“添加资源” =>“添加现有文件”下

然后您就可以像这样访问它。

var html = Resources.YourFileName;

记住要使用添加

using YourProject.Properties;

答案 3 :(得分:0)

这取决于模板更改的频率以及更改的模板。 E.g:

由应用程序的用户更改,更改是紧急的并且可能经常发生:

  • 可能最好存储在数据库中,并在每次发送电子邮件时加载。

由开发人员(即您)更改,更改很少发生,而不是紧急:

  • Web服务器上的文本文件,将它们加载到缓存中并将其存储在那里,只在缓存丢失或应用程序重新启动时重新加载它们。

答案 4 :(得分:0)

您可以在.html file中存储电子邮件模板。然后以支持您想要包含的参数的方式对其进行格式化。 e.g。

<head>
<title></title>
</head>
<body>
    Hello <!--Name--> ,
    This is a test template 
    User Name: <!--UserName-->
    .............................
    .............................
</body>
</html>

每当您向用户发送电子邮件时,您都希望将模板设置为特定于用户,因此您可以在运行时替换该参数。

答案 5 :(得分:0)

感谢大家提供有关他们如何处理的见解。我从这里收集了很多知识。我喜欢@MartinHN使用Razor解析器和具体的数据模型。

但是,它对我来说效果不佳。

要求:

  • 我必须存储电子邮件模板,以便我可以显示相同的内容 利益相关者随时。因此它应该可以浏览 内联网 - 最好通过sae网站作为托管API。

  • 前端设计人员应该能够轻松修改模板。 因此,我希望以普通的HTML格式存储它,以便设计人员这样做 不必经过太多的技术细节。

  • 电子邮件模板应易于修改 管理员(未来要求)。在不久的将来,会有 SMS,Screen的不同通知。因此模板是 不同。

根据这些要求,我做了以下工作:

  1. 由于我使用的是MVC,我创建了一个名为“STATIC”的文件夹 可以直接浏览(和MVC引擎/ http处理程序 排除此文件夹执行其MVC活动。)

    通过这种方法,我可以很容易地实现第一个要求和我 可以将我的链接发送给利益相关者 http://api.aksdfjl.com/static/welcomeemailtemplate.html

  2. 每个电子邮件模板都有自己的html,因此很容易 设计者访问它并在它们的存储库中引用它作为 存储库文件夹的快捷方式。 Html有内联CSS,它是 完全是一个独立的HTML - 每个电子邮件。

  3. 最后一个主要要求是维护这些设计,用户可以对其进行修改。那么我绝对不想通过文件系统处理。我所做的是现在这些通知存储到数据库中,我将它们初始化一次。之后,管理员面板上有一个wysiwyg html编辑器,可以给他们一个快速预览,并控制它应该发送到什么。

  4. 现在我想确保未来的要求很容易处理,因为我的公司正在为不同的模式引入不同的通知,例如电子邮件,屏幕,短信通知。我决定借助存储这些答案的模板初始化XML来扩展软件设计。

    所有名为的模板的母亲 - MessageTemplates.xml存储了初始化不同类型模板所需的不同信息,即电子邮件,短信,屏幕等。

    enter image description here

    以下是代码的样子。

     [HttpGet]
            [Route("applications/initializenotificationtemplate")]
            public IHttpActionResult InitializeNotificationTemplate()
            {
                return
                    InitializeNotificationTemplate(Path.Combine(HostingEnvironment.ApplicationPhysicalPath,
                        @"Static\InitializeData\MessageTemplates.xml"));
            }
    
    
    
    
    [NonAction]
            public IHttpActionResult InitializeMailTemplate(string filePath)
            {
                try
                {
                    _applicationService.InitializeTemplate(filePath);
                    return Ok("Application Notification templates are initialized.");
                }
                catch (Exception ex)
                {
                    return InternalServerError(ex);
                }
            }
    

    _applicationService.InitializeTemplate具有以下定义:

    public bool InitializeTemplate(string filePath)
            {
                if (string.IsNullOrEmpty(filePath))
                {
                    throw new ArgumentNullException("File Path");
                }
    
                if (!File.Exists(filePath))
                {
                    throw new FileNotFoundException(filePath);
                }
    
    
                var data = _notificationTemplateService.Get();
                var exceptionMessages = string.Empty;
    
                if (data != null)
                {
                    var historicalTemplates = data.ToList();
                    historicalTemplates.ForEach((d) => _notificationTemplateService.Delete(d, out exceptionMessages));
                }
    
                XDocument xmlDocument = XDocument.Load(filePath);
                IEnumerable<NotificationTemplate> templates = (from template in xmlDocument.Descendants("Template")
                                                               select new NotificationTemplate()
                                                               {
                                                                   Title = template.Element("Subject").Value,
                                                                   Description = template.Element("Body").Value,
                                                                   Type = (NotificationTypeOptions)Enum.Parse(typeof(NotificationTypeOptions), template.Element("Type").Value, true),
                                                                   Category = (NotificationCategoryOptions)Enum.Parse(typeof(NotificationCategoryOptions), template.Attribute("category").Value, true),
                                                               }).ToList();
    
                foreach (var t in templates)
                {
                    var path = Path.Combine(Path.GetDirectoryName(filePath), Regex.Replace(t.Description, @"\t|\n|\r| ", ""));
                    if (File.Exists(path))
                    {
                        StreamReader reader = new StreamReader(path);
                        t.Description = reader.ReadToEnd();
                    }
                    else
                    {
                        t.Description = string.Empty;
                    }
                }
    
                return _notificationTemplateService.InsertRange(templates, out exceptionMessages);
            }
    

    这就是我的模型与数据库模型(代码优先 - EF方法)相同的样子。

     public class NotificationTemplate  : IdentityBase
        {
            public string Category { get; set; }
            public NotificationTypeOptions Type { get; set; }
            public string Title { get; set; }
            public string Description { get; set; }
    
            public NotificationTemplate()
            {
                Type = NotificationTypeOptions.Email;
            }
        }
    
     [Flags]
        public enum NotificationTypeOptions
        {
            Email = 0,
            Screen = 1,
        }
    

    第一次,当我安装我的应用程序时,我调用初始化API调用,将我的通知模板安装到数据库中,所有其他选项都可用并可以使用。

    现在通过这种方法,我让每个人都对组织感到满意,并且它有很大的优势来进一步扩展这一点,因此我也很容易引入新的模板。