MailMergeLib - 适用于 .NET 的邮件客户端库
MailMergeLib 是一个用 C# 编写的 SMTP 模板邮件客户端库,它提供了舒适的邮件合并功能和 SMTP 故障转移功能。它适用于 .NET Framework 和 .NET Core。
- 从 GitHub 下载 MailMergeLib 5 源代码
- 获取 MailMergeLib 5 NuGet 包
- 下载旧版 MailMergeLib 4.03 使用 System.Net.Mail - 包含源代码、文档和一个小型演示项目 - 833.3 KB
演变
早在 2007 年,当 MailMergeLib
完成后,发现 Microsoft System.Net.Mail
大约有 20 个丑陋的问题。其中许多可以通过使用 System.Reflection
来破解其系统来修复。缺点是 .NET Framework 的每个新版本都需要进行大量的测试和重写错误修复。
这些错误已报告给 Microsoft,最终其中一半得到了纠正。
2015 年初,Jeffrey Stedfast 推出了他的 MimeKit 和 MailKit 开源库的第一个版本。正如他在 代码审查 中所写,他坚信可以有比 System.Net.Mail
更好的东西。他确实成功了——不仅生成了符合 RFC 标准的出站邮件消息,还提供了 IMAP 和 POP3 功能。这是重写 MailMergeLib
代码的起点,现在使用 MailKit
和 MimeKit
而不是 System.Net.Mail
。
引言
应用程序需要发送电子邮件的场合有很多:网页中的反馈表单、网络邮件、日志记录器等等。有许多商业解决方案可用:EASendMail SMTP 组件、MailBee.NET SMTP 组件、Aspose.Network.Mail 或 aspNetEmail,仅举几例。如果您正在寻找一个具有源代码、提供可比功能的免费解决方案,那么仔细研究 MailMergeLib
是值得的。
邮件消息生成
- 电子邮件模板可以在**收件人**、**主题**、HTML 和/或纯**文本**、**附件**甚至**邮件头**方面完全个性化。占位符以数据源中的变量名插入到花括号之间,例如:
{MailboxAddress.Name}
或带格式参数,例如{Date:yyyy-MM-dd}
。(在MailMergeLib
的早期版本中,这是通过正则表达式实现的。现在实现了极快的 SmartFormat 解析器。) - HTML 文本可以包含来自本地硬盘的图像,这些图像将自动作为内联附件插入。
- 对于 HTML 文本,
MailMergeLib
可以生成纯文本表示。 - 附件源可以是文件、流或字符串。
- 用于向多个收件人发送电子邮件合并消息的数据源可以是任何
IEnumerable
对象以及DataTable
。用于单个电子邮件的数据源可以是以下任何类型:Dictionary<string,object>
、ExpandoObject
、DataRow
、任何类实例或匿名类型。对于类实例,甚至允许使用无参数方法的名称。 - 通过使用 SmartFormat.NET,电子邮件中的占位符可以使用
string.Format
中已知的所有功能进行格式化。SmartFormat 是一个接近string.Format
速度的解析器,但带来了许多额外选项,例如许多语言的轻松复数化。 - 生成的电子邮件是来自 MimeKit 的
MimeMessage
,MimeKit 是一个出色的用于创建和解析电子邮件的工具,涵盖所有相关的 MIME 标准,确保电子邮件不会被识别为垃圾邮件。 - 支持国际电子邮件地址格式。
发送电子邮件
- 实际上无限数量的并行任务,用于向大量收件人发送个性化电子邮件。
- 每个任务的
SmptClient
可以获得自己的预配置设置,以便例如可以使用多个邮件服务器来完成一个发送作业。 - 通过许多事件可以轻松观察处理电子邮件的进度。
- SMTP 故障可以通过提供备份配置自动解决。这种容错能力对于无人值守的生产系统至关重要。
- SMTP 配置可以存储/从标准 XML 文件中恢复。
- 电子邮件是使用 MailKit(MimeKit 的姊妹项目)中的
SmptClient
发送的。MailKit 具有高度灵活性,可以配置为几乎您能想到的任何场景。 - 除了发送,电子邮件还可以存储在 MIME 格式的文本文件中,例如,如果要使用 IIS 或 Microsoft Exchange 的“提取目录”。如果需要,这些文件可以加载回 MimeKit 的
MimeMessage
中。
左键单击 gadget 并拖动以移动它。左键单击 gadget 的右下角并拖动以调整其大小。右键单击 gadget 以访问其属性。
- 对电子邮件消息生成和分发整个过程的细粒度控制。
- 明显优于 .NET
System.Net.Mail
。 - 消息和 SMTP 的配置设置可以存储到 XML 文件并从中加载。
- 符合 RFC 标准。
- 我们请求您不要使用
MailMergeLib
发送未经请求的批量电子邮件。
Using the Code
配置
基本设置
MailMergeLib
的配置由两个主要部分组成:MessageConfig
和 SenderConfig
。
首先,设置用于在配置保存到文件时加密和解密网络凭据的密钥。这并非绝对安全,但总比将凭据显示为纯文本要好。
Settings.CryptoKey = "SecretCryptoKey"; // don't use this key
一个相当小的配置看起来像这样
var settings = new Settings
{
MessageConfig =
{
CharacterEncoding = Encoding.UTF8,
StandardFromAddress = new MailboxAddress("sender name", "sender@example.com"),
// necessary for proper formatting of placeholders:
CultureInfo = CultureInfo.CurrentCulture,
// especially in case a placeholder results in an empty address:
IgnoreIllegalRecipientAddresses = true,
Xmailer = "MailMergeLib 5"
},
SenderConfig =
{
SmtpClientConfig = new[]
{
new SmtpClientConfig()
{
MessageOutput = MessageOutput.SmtpServer,
SmtpHost = "some.host.com",
SmtpPort = 587,
NetworkCredential = new Credential("user", "password"),
// identify active configuration in case you have more than one
Name = "StandardConfig",
// number of trials until an exception is thrown:
MaxFailures = 3,
// number of milliseconds before a retry to send will happen:
RetryDelayTime = 1000,
// number of milliseconds between messages:
DelayBetweenMessages = 0,
// used in SMTP Hello command
ClientDomain = "mail.example.com"
}
}
}
};
设置可以保存和恢复
var settings = Settings.Deserialize("MailMergeLib.config");
settings.Serialize("MailMergeLib.config");
事件处理程序
MailMergeSender
允许自定义事件处理程序。MailMergeSender
将触发 OnBeforeSend
、OnAfterSend
、OnSendFailure
、OnMergeBegin
、OnMergeComplete
和 OnMergeProgress
事件。示例
var mms = new MailMergeSender {Config = settings.SenderConfig};
mms.OnAfterSend += (sender, args) => { // do something useful here };
创建新消息
邮件消息的数据源
当然,数据源是邮件合并最重要的主题。
首先,让我们创建一个 Dictionary
,它将包含消息中 {placeholders}
的值。占位符是例如 IList
项属性中的花括号内的名称,或数据表的列名。
var variables = new Dictionary<string, object>()
{ { "Email", "sample@example.com" }, {"Name", "John Specimen"} };
{placeholders}
可以用于电子邮件地址、主题、纯文本或 HTML 正文、文本附件内容和附件名称(包括 HTML 正文的嵌入图像)。
因此,如果需要 2 个收件人,您可以创建一个匿名类型
var variables = new[]
{
new {Email = "sample1@example.com", Name = "John Specimen"}
new {Email = "sample2@example.com", Name = "Mary Specimen"}
};
当使用 O/R 映射器时,实体字段可能看起来像这样:Department.Leader.FirstName
。因此,您可以将字段名作为占位符使用“点符号”:{Department.Leader.FirstName}
。
邮件正文
接下来,我们创建一个新消息,包含主题、纯文本和 HTML 正文部分。
var mmm = new MailMergeMessage("Personal subject for {Name}", "This is pure text for {Name}",
"<html><head><title>No title</title></head>
<body>This is HTML text for {Name}</body></html>") {Config = settings.MessageConfig};
如果 HTML 部分包含图像,MailMergeLib
将自动将其作为“链接资源”添加到电子邮件中。图像源必须包含本地文件的路径。路径也可以包含 {placeholders}
。
<img src="file:///full-path-to-your-image-file.jpeg" alt="Image" width="100" height=100"/>
除了为每张图片提供完整路径外,还可以为图片设置路径。
mmm.Config.FileBaseDirectory = "Path-to-images";
您想看看最终的消息会是什么样子吗?只需将其保存到文件并使用文本编辑器或您的电子邮件应用程序(例如 Microsoft Outlook 或 Mozilla Thunderbird)进行查看。
mmm.GetMimeMessage(variables).WriteTo("enter-your-filename-here.eml");
如果不需要手动提供纯文本部分,MailMergeLib
可以完成将 HTML **转换为纯文本**的工作。
mmm.PlainText = mmm.ConvertHtmlToPlainText();
为了完成这项工作,MailMergeMessage
提供了 ParsingHtmlConverter
用于将 HTML 转换为纯文本。它使用开源库 AngleSharp^,其方法类似于 John Gruber 的 Markdown^。它将**电子邮件中**(而非网页中)最常见的 HTML 标签和属性转换为纯文本,效果相当不错。如果 AngleSharp
不可用或失败,则使用非常基本的 RegExHtmlConverter
(类似于 此解决方案^),除非您提供实现了 IHtmlConverter
的自定义转换器。
格式化功能
占位符和格式化功能允许代码和设计分离。为了更改电子邮件内容,只需更改纯文本或 HTML 文本的模板文件,无需修改代码即可完成。
通常,{placeholders}
的格式化通过内置于 MailMergeLib
中的 SmartFormat.Net
与 string.Format
完全兼容。有关详细信息,请参阅 SmartFormat Wiki。SmartFormat.Net
作为 MailMergeMessage
的 SmartFormatter
属性公开。
以下是一些与 string.Format
具有相同功能的示例
"{Date:yyy-MM-dd}" for a variable of type DateTime
"You are visitor number {NumOfVisitors}" for a variable of type int
"{Name} from {Address.City}, {Address.State}" for a variable which is an instance of class "user"
SmartFormat.Net
附带的格式化扩展
"You have {emails.Count} new {emails.Count:message|messages}" // pluralization
"{Users:{Name}|, |, and } liked your comment" // a list of users
"{Name:choose(null|):N/A|empty|{Name}}" // assuming an object with property "Name"
// which can be null, empty or a string
附件
您可能还希望通过向文件名添加占位符来添加一些个性化附件。例如:
mmm.FileAttachments.Add
(new FileAttachment("testmail_{Username}.pdf", "sample.pdf", "application/pdf"));
这就是添加 string
附件的方法
mmm.StringAttachments.Add(new StringAttachment
("Some programmatically created content", "logfile.txt", "text/plain"));
邮件地址
要发送邮件,我们至少需要提供一个收件人地址和发件人地址。同样,使用占位符可以创建个性化电子邮件。
mmm.MailMergeAddresses.Add(new MailMergeAddress(MailAddressType.From, "whatever@example.com"));
mmm.MailMergeAddresses.Add(new MailMergeAddress(MailAddressType.To, "{Name}", "{Email}"));
杂项
如果您使用包含变量的数据源,很可能会遇到收件人的电子邮件字段为空的情况。这就是为什么您可能希望在地址为空时不要抛出异常。
mmm.Config.IgnoreEmptyRecipientAddr = true;
想更改 MailMergeLib
的标识?将邮件的 Xmailer
标头设置为您喜欢的任何内容。
mmm.Config.Xmailer = "MailMergeLib 5.0";
发送消息
使用 MailMergeSender
非常简单:创建类的实例并提供配置章节中解释的一些设置。
创建配置好的 MailMergeSender
设置邮件发送器
var mailSender = new MailMergeSender {Config = settings.SenderConfig};
开始传输
对于 Send
作业,有几种替代方案
- 以**异步**操作发送**单条消息**
var dict = new Dictionary<string, object>() { { "Email", "sample@example.com" }, {"Name", "John Specimen"} }; mailSender.SendAsync(mmm, (object) dict);
- 以**异步**操作发送
DataSource
中**所有项目**的所有消息var variables = new[] { new {Email = "sample1@example.com", Name = "John Specimen"} new {Email = "sample2@example.com", Name = "Mary Specimen"} }; mailSender.SendAsync(mmm, variables);
- 以**同步**操作发送
DataSource
中**所有项目**的消息mailSender.Send(mmm, variables);
- 或者只是**同步**发送**单条消息**,提供一个包含名称/值对的
Dictionary
mailSender.Send(mmm, (object) dict);
SMTP 故障转移配置
当您在 SenderConfig
中定义多个 SMTP 配置时,第一个 SMTP 配置将是用于发送消息的标准配置。如果通过标准配置发送失败,将使用第二个配置。
这在无人值守的环境中(例如 Web 服务器上的计划任务)非常有用。
SenderConfig =
{
SmtpClientConfig = new[]
{
new SmtpClientConfig()
{
MessageOutput = MessageOutput.SmtpServer,
SmtpHost = "some.host.com",
SmtpPort = 25,
NetworkCredential = new Credential("user", "password"),
Name = "Standard Config",
MaxFailures = 3,
DelayBetweenMessages = 500
},
new SmtpClientConfig()
{
MessageOutput = MessageOutput.SmtpServer,
SmtpHost = "some.otherhost.com",
SmtpPort = 587,
NetworkCredential = new Credential("user2", "password2"),
Name = "Backup Config",
DelayBetweenMessages = 1000
}
},
MaxNumOfSmtpClients = 5
}
使用多个 SmtpClient 发送消息
设置 mailSender.Config.MaxNumOfSmtpClients = 5
将使用五个并行 SmtpClient
异步发送消息。
当定义多个 SMTP 配置时,每个配置将交替分配给 SmtpClient
。故障转移的工作方式也会略有不同:如果发生故障,将使用除当前配置之外的第一个配置。
取消发送操作
异步 Send
操作可以随时取消
mailSender.SendCancel();
影响错误处理
超时(毫秒)
mailSender.Config.Timeout = 100000;
发送消息最终失败前的最大失败次数
mailSender.Config.MaxFailures = 3;
失败之间的重试延迟时间
mailSender.Config.RetryDelayTime = 3000;
每条消息之间的延迟时间
mailSender.Config.DelayBetweenMessages = 1000;
结论
新版本的 MailMergeLib
使用 MimeKit
和 MailKit
。它们是出色的开源库,可以对电子邮件消息生成和分发整个过程进行非常细致的控制。最重要的是,它们生成的电子邮件消息符合 RFC 标准。
建议从旧版本迁移到 MailMergeLib
版本 5。
特别感谢
- Jeffrey Stedfast 的 MimeKit 和 MailKit 开源库
- Florian Rappl 的开源 AngleSharp HTML 解析器
- John Gruber 分享他的 Markdown 基于 xslt 的文本到 HTML 转换工具
- 所有在论坛中提供反馈和投票的用户
版本
- 2007-07-10: 初始公开发布
MailMergeLib
2.0,使用System.Net.Mail
- 2009-12-23:
MailMergeLib
3.0,使用System.Net.Mail
- 2010-05-01:
MailMergeLib
4.0,使用System.Net.Mail
- 2016-09-04:
MailMergeLib
5.0 - 使用 MimeKit 和 MailKit 进行底层操作的重大重写 - 2016-10-23: 自
MailMergeLib
5.1.0 起也支持 .NET Core
最新版本的 MailMergeLib
可在 GitHub 上获取:https://github.com/axuno/MailMergeLib