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






4.91/5 (41投票s)
一个简单、用户友好且灵活的框架,可以一次性处理所有电子邮件模板文件。
引言
大多数 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 |
邮件的格式,可以是 Text 或 Html 。 |
文件 |
模板文件的路径。可以是绝对路径或相对路径。 |
模板 |
包含一个或多个 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
会替换模板的Subject
和Body
中的键。- 如果属性值为
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 日。