65.9K
CodeProject 正在变化。 阅读更多。
Home

电子邮件模板:处理模板文件的通用解决方案

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (41投票s)

2004年11月5日

CPOL

7分钟阅读

viewsIcon

181199

downloadIcon

1334

一个简单、用户友好且灵活的框架,可以一次性处理所有电子邮件模板文件。

引言

大多数 Web 应用程序,以及一些桌面应用程序,都需要不时发送电子邮件:注册和激活邮件、错误警告、确认邮件等。如果这些电子邮件的内容不是通过数据库或 CMS 获取的,它们主要存储在文本、HTML 或 XML 文件中。我一直认为处理模板文件是一项繁琐的任务,所以我提出了这个能够显著简化事情的解决方案。

基本上,这个库会为您处理任意(可选本地化)模板文件的组织。我真的很想保持简单,并获得一个不依赖于数据库的通用解决方案。因此,您只需创建一个单独的 XML 文件来链接您的模板即可开始工作。

在运行时使用该库非常简单。要检索并向给定收件人发送本地化的模板,只需三行代码即可完成。

//get the template handler
TemplateHandler handler = TemplateHandler.Instance;

//get a french registration template
MailTemplate template = handler["registration", 
                        new CultureInfo("fr"];

//send the template 
handler.Send(template, "anybody@xxx.xxx");

目录

设置 XML 文件

您应用程序的所有模板都在一个 XML 文件中配置。您需要通过将 Evolve.TemplateConfiguration 键添加到应用程序配置文件(web.config / App.config)的 appSettings 部分来告诉框架该文件的位置。在 Web 应用程序中,您可以使用波浪号 (~) 来指定应用程序的虚拟根目录。

<appSettings>
  <add key="Evolve.TemplateConfiguration" 
          value="~/mailings/templates.config" />
</appSettings>

这是一个简单的配置文件示例。它包含两个*模板组*的设置。

  • 论坛注册:电子邮件模板有英语和德语版本。
  • 电子贺卡通知:无本地化(仅限英文模板)。
<?xml version="1.0" encoding="utf-8" ?> 

<TemplateConfiguration>
  <BaseDirectory>template samples</BaseDirectory>
  <SmtpServer>mail.xxx.xxx</SmtpServer>

  <Groups>

    <!-- first group, localized templates -->
    <TemplateGroup TemplateGroupId="forumregistration"
      Sender="forums@xxx.xxx"
      MailFormat="Text">

      <Templates>

        <Template IsDefault="true">
          <Subject>your registration</Subject>
          <File>forum/registration_en.txt</File>
        </Template>

        <Template Locale="de">
          <Subject>Ihre Registrierung</Subject>
          <File>forum/registration_de.txt</File>
        </Template>
  
      </Templates>
     
    </TemplateGroup>

  
    <!-- second group, no localization -->
    <TemplateGroup TemplateGroupId="greetingcard"
      Sender="ecards@xxx.xxx"
      MailFormat="Html">

      <Templates>
         <Template IsDefault="true">
           <Subject>You got an eCard from {0}</Subject>
           <File>ecards/notification.txt</File>
         </Template>
      </Templates>
    </TemplateGroup>

  </Groups>

</TemplateConfiguration>

TemplateConfiguration 元素

这是配置文件中的根元素。它包含适用于所有模板的通用设置。

BaseDirectory 可选但推荐。如果设置,模板的相对文件路径将基于此文件夹确定。对于 Web 应用程序,您可以使用波浪号 (~) 来指定虚拟根目录。
SmtpServer 可选但推荐。用于发送消息的 SMTP 服务器。
包含一个或多个 TemplateGroup 声明。

TemplateGroup 元素

如您所见,配置文件包含多个 TemplateGroup 元素。每个模板组都需要一个唯一的 ID,用于请求给定的模板。

TemplateGroupId 组的唯一 ID,用于在运行时从 TemplateHandler 控制器类请求模板。
Sender 用于电子邮件的发件人地址。
MailFormat 邮件的格式,可以是 TextHtml
文件 模板文件的路径。可以是绝对路径或相对路径。
模板 包含一个或多个 Template 声明。

Template 元素

每个模板组都包含一个 Templates 列表,其中有一个或多个 Template 元素。给定组的所有模板都包含针对同一过程(例如,注册确认)但语言不同的消息。

区域设置 (Locale) 定义模板的语言。示例:en(英语)、de(德语)、de-ch(德语 [瑞士])、fr-ch(法语 [瑞士])。在运行时,您将处理相应的 CultureInfo 对象。
IsDefault 如果设置为 true,则在运行时请求未知 CultureInfo 的模板时将返回此模板。在这种情况下,不需要 Locale 属性。
主题 如果通过 TemplateHandler 发送模板,则为邮件主题。
文件 模板文件的路径。可以是绝对路径或相对路径。

代码使用

MailTemplate

MailTemplate 对象封装了模板的所有设置。

TemplateGroupId XML 文件中 TemplateGroup 元素定义的组 ID。
区域设置 (Locale) 模板的本地化信息。在模板组的默认模板上,这是 CultureInfo.InvariantCulture
主题 根据配置文件,邮件的主题。
正文 存储在模板文件中的文本。

您可以轻松调整和格式化 MailTemplate 对象的​​内容。每次从 TemplateHandler 请求 MailTemplate 时,都会创建一个新实例。有关格式化内容的详细信息,请参阅格式化您的内容

TemplateHandler

TemplateHandler 控制器类通过提供两个索引器来让您访问特定模板。它们接受 TemplateGroupId 和一个可选的 CultureInfo 参数用于本地化。一旦您引用了 MailTemplate 对象,您就可以在代码中处理它,并最终使用其中一个 Send 重载将其发送给一个或多个收件人。

TemplateHandler handler = TemplateHander.Instance;

//get the default template of the above sample
MailTemplate template1 = handler["forumregistration"];

//get the german template
MailTemplate template2 = handler["forumregistration", 
                         new CultureInfo("de")];

//this returns also the default template, as there is no french template:
MailTemplate template3 = handler["forumregistration", 
                         new CultureInfo("fr")];

//send the template
handler.Send(template3, "info@xxx.xxx");

挂钩到发送过程

虽然在大多数情况下,仅通过 TemplateHandler 发送邮件可能就足够了,但在某些情况下您可能希望拥有更多控制权。一种解决方案是自己创建和发送电子邮件。另一种方法是使用接受 TemplateCallbackHandler 类型委托的 Send 重载。

public delegate void TemplateCallbackHandler(MailTemplate template, 
                              MailMessage message);

如果您使用此功能,则在将 MailMessage 发送给收件人之前,框架会调用一个回调处理程序。这让您可以完全控制电子邮件。下面的示例使用回调在将 PDF 文件附加到邮件之前将其发送给收件人。

private void Send(MailTemplate template)
{
  TemplateHandler handler = TemplateHandler.Instance;

  //create delegate  
  TemplateCallbackHandler cb;
  cb = new TemplateCallbackHandler(HandleMessageCallback));

  //send message
  handler.Send(template, "info@xxx.xx", cb);
}



//this is the callback handler
private void HandleMessageCallback(MailTemplate template, 
                                          MailMessage message)
{
  //add file
  MailAttachment att = new MailAttachment("terms.pdf");
  message.Attachments.Add(att);
}

格式化您的内容

您的大部分模板将包含动态部分:您需要包含 ID 和密码、电子邮件地址等。框架对此没有任何假设。假设您需要格式化电子邮件的主题。在此示例中,我只包含格式占位符 {0}

<Template IsDefault="true">
  <Subject>You got an eCard from {0}</Subject>
  <File>ecards/notification.txt</File>
</Template>

为了调整主题,我的代码如下所示:

MailTemplate template = handler["greetingcard"];
template.Subject = String.Format(template.Subject, "Mr. Tarantino");

handler.Send(template, "info@xxxx.xx");

这将生成一封主题为 *You got an eCard from Mr. Tarantino* 的邮件。

PropertyMapper 辅助类

但是,我构建了一个简单的辅助类,可以为您自动分配值给占位符。您没有必要使用它,但它可能会很有用。PropertyMapper 类背后的简单思想是,您可以使用特殊标记包围的键来格式化模板。

示例

Hello #?FirstName?#
Your email address is #?EmailAddress?#

现在,假设您有一个 User 类,它提供的属性与这些键匹配。

您现在可以做的是将 User 类和 MailTemplate 提供给 PropertyMapper。它将用相应的属性值替换匹配 User 类公共属性的所有键:#?FirstName?# 被替换为 FirstName 属性的值,#?EmailAddress?# 获取 EmailAddress 属性的值,依此类推。代码如下所示:

//get a user class
User user = new User(123);

//get a mail template
MailTemplate template = GetUserTemplate();

//create a mapper class with the User instance
PropertyMapper mapper = new PropertyMapper(user);

//map the object properties to the template
mapper.MapTemplate(template);

一些说明

  • 请注意,开始标记(#?)和结束标记(?#)不相同!.
  • 如果模板包含与任何属性都不匹配的键,它们将不会被更改。如果您想用两个不同对象的属性替换键,您可以轻松地交换对象并再次调用 MapTemplate
  • MapTemplate 会替换模板的 SubjectBody 中的键。
  • 如果属性值为 null,则该键将被替换为空字符串。
  • 您也可以通过调用 MapContent 来传递 string 而不是 MailTemplate 对象。传递的 string 不会被更改,但会返回一个新的 string

MailTemplate 生命周期

下图显示了从模板检索到其传输的所有过程。

关注点

本文档未涵盖框架的内部机制。但是,如果您想了解其工作原理,代码有很好的文档记录,应该很容易理解。一些关注点:

  • 配置文件使用 .NET 内置的 XML 反序列化(使用 XmlSerializer 类)进行解析。我喜欢 XML 序列化,因为它使事情变得如此简单!Evolve.Util.MailTemplates.Xml 命名空间包含与配置文件元素匹配的类。
  • PropertyMapper 类使用正则表达式来检索模板的占位符。当然, there is Reflection involved to access the properties of submitted objects. (这里涉及到反射来访问提交对象的属性。)

ZIP 文件包含源代码、一个使用不同模板工作的示例(WinForms)应用程序以及一些 NUnit 测试。

新闻稿

这是该库的第一个版本,可能还会有一些增强/修复。如果您正在使用该库,我建议您不时回来查看。如果您希望保持更新,可以在我的网站上订阅相应的新闻通讯:新闻通讯订阅

结论

这是一个方便的小库,如果您使用基于文件的模板,它可以让您的工作更轻松。它非常简单——这正是它所需要的。祝您使用愉快 :-)。

历史

  • 1.0.0:2004 年 11 月 3 日。
© . All rights reserved.