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

MailMergeLib - 适用于 .NET 的邮件客户端库

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.95/5 (128投票s)

2007年7月10日

MIT

9分钟阅读

viewsIcon

918688

downloadIcon

10185

MailMergeLib 是一个用 C# 编写的 SMTP 模板邮件客户端库,它提供了舒适的邮件合并功能和 SMTP 故障转移功能。它适用于 .NET Framework 和 .NET Core。

Screenshot of a merged email

演变

早在 2007 年,当 MailMergeLib 完成后,发现 Microsoft System.Net.Mail 大约有 20 个丑陋的问题。其中许多可以通过使用 System.Reflection 来破解其系统来修复。缺点是 .NET Framework 的每个新版本都需要进行大量的测试和重写错误修复。

这些错误已报告给 Microsoft,最终其中一半得到了纠正。

2015 年初,Jeffrey Stedfast 推出了他的 MimeKitMailKit 开源库的第一个版本。正如他在 代码审查 中所写,他坚信可以有比 System.Net.Mail 更好的东西。他确实成功了——不仅生成了符合 RFC 标准的出站邮件消息,还提供了 IMAP 和 POP3 功能。这是重写 MailMergeLib 代码的起点,现在使用 MailKitMimeKit 而不是 System.Net.Mail

引言

应用程序需要发送电子邮件的场合有很多:网页中的反馈表单、网络邮件、日志记录器等等。有许多商业解决方案可用:EASendMail SMTP 组件MailBee.NET SMTP 组件Aspose.Network.MailaspNetEmail,仅举几例。如果您正在寻找一个具有源代码、提供可比功能的免费解决方案,那么仔细研究 MailMergeLib 是值得的。

邮件消息生成

  • 电子邮件模板可以在**收件人**、**主题**、HTML 和/或纯**文本**、**附件**甚至**邮件头**方面完全个性化。占位符以数据源中的变量名插入到花括号之间,例如:{MailboxAddress.Name} 或带格式参数,例如 {Date:yyyy-MM-dd}。(在 MailMergeLib 的早期版本中,这是通过正则表达式实现的。现在实现了极快的 SmartFormat 解析器。)
  • HTML 文本可以包含来自本地硬盘的图像,这些图像将自动作为内联附件插入。
  • 对于 HTML 文本,MailMergeLib 可以生成纯文本表示。
  • 附件源可以是文件、流或字符串。
  • 用于向多个收件人发送电子邮件合并消息的数据源可以是任何 IEnumerable 对象以及 DataTable。用于单个电子邮件的数据源可以是以下任何类型:Dictionary<string,object>ExpandoObjectDataRow、任何类实例或匿名类型。对于类实例,甚至允许使用无参数方法的名称。
  • 通过使用 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 的配置由两个主要部分组成:MessageConfigSenderConfig

首先,设置用于在配置保存到文件时加密和解密网络凭据的密钥。这并非绝对安全,但总比将凭据显示为纯文本要好。

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 将触发 OnBeforeSendOnAfterSendOnSendFailureOnMergeBeginOnMergeCompleteOnMergeProgress 事件。示例

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.Netstring.Format 完全兼容。有关详细信息,请参阅 SmartFormat WikiSmartFormat.Net 作为 MailMergeMessageSmartFormatter 属性公开。

以下是一些与 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 作业,有几种替代方案

  1. 以**异步**操作发送**单条消息**
    var dict = new Dictionary<string, object>() 
    { { "Email", "sample@example.com" }, {"Name", "John Specimen"} };
    mailSender.SendAsync(mmm, (object) dict);
  2. 以**异步**操作发送 DataSource 中**所有项目**的所有消息
    var variables = new[]
       {
         new {Email = "sample1@example.com", Name = "John Specimen"}
         new {Email = "sample2@example.com", Name = "Mary Specimen"}
       };
     mailSender.SendAsync(mmm, variables);
  3. 以**同步**操作发送 DataSource 中**所有项目**的消息
    mailSender.Send(mmm, variables);
  4. 或者只是**同步**发送**单条消息**,提供一个包含名称/值对的 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 使用 MimeKitMailKit。它们是出色的开源库,可以对电子邮件消息生成和分发整个过程进行非常细致的控制。最重要的是,它们生成的电子邮件消息符合 RFC 标准。

建议从旧版本迁移到 MailMergeLib 版本 5。

特别感谢

  • Jeffrey Stedfast 的 MimeKitMailKit 开源库
  • 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

© . All rights reserved.