HolidaysMailer






3.95/5 (10投票s)
一个自动发送邮件的应用程序
引言
我遇到了向收件人列表发送电子邮件的问题,但收件人之间彼此不知道(如果存在其他收件人的话)。具体来说,我想给所有的熟人发送节日问候信息,而无需手动发送单独的消息。
背景
有三种标准的解决方案可以向多个收件人发送电子邮件,但它们都不能令人满意地完成我需要完成的任务。
- 填写电子邮件发送表单的收件人:字段 - 每个收件人都会看到所有其他收件人。
- 将除一个收件人外的所有人放入抄送:(Carbon Copy:)框中 - 这再次引发了第1点的担忧。
- 将除一个收件人外的所有人放在密送:(Black Carbon Copy:)字段中 - 每个收件人都能看到“收件人:”选择中的收件人,但看不到密送区域中的其他任何人。
当用户期望收到单独发送给自己的电子邮件时,这些选项都不可靠。
设计解决方案
最自然的选择是向“收件人:”字段中指定的单个收件人重复发送电子邮件。这无法手动高效完成,因此必须设计一种自动解决方案。
一个专门设计的应用程序(或脚本)应该
- 读取发件人邮件账户所在邮件服务器的电子邮件配置:SMTP(简单邮件传输协议)主机名、SMTP端口以及邮件服务器上SSL(安全套接字层)的可用性。
- 检索发件人的姓名,以便收件人稍后查看,以及其账户名称和密码。
- 获取要发送的消息主题和内容。
- 获取必须发送消息的姓名和电子邮件地址列表。
- 逐一发送电子邮件。
- 打印电子邮件发送状态的报告。
一个合理的选择是从应用程序用户在运行应用程序之前设置的配置文件中读取这些数据。
配置文件
HolidaysMailer
配置文件使用的格式是XML,如下面的EmailConfig.xml文件所示。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE EmailConfiguration [
<!ELEMENT EmailConfiguration (SmtpHost, SmtpPort,
FromAddress, FromName, Subject, Content, Addresses)>
<!ATTLIST EmailConfiguration EnableSSL (true|false) #REQUIRED>
<!ELEMENT SmtpHost (#PCDATA)>
<!ELEMENT SmtpPort (#PCDATA)>
<!ELEMENT FromAddress (#PCDATA)>
<!ELEMENT FromName (#PCDATA)>
<!ELEMENT Subject (#PCDATA)>
<!ELEMENT Content (#PCDATA)>
<!ELEMENT Addresses (Person*)>
<!ELEMENT Person (Name, Email)>
<!ELEMENT Name (#PCDATA)>
<!ELEMENT Email (#PCDATA)>
]>
<EmailConfiguration EnableSSL="true">
<SmtpHost>smtp.gmail.com</SmtpHost>
<SmtpPort>587</SmtpPort>
<FromAddress>mock.email@gmail.com</FromAddress>
<FromName>Mihnea Radulescu</FromName>
<Subject>Happy Easter</Subject>
<Content>Happy Easter and kindest wishes to you!
Yours sincerely,
Mihnea Radulescu</Content>
<Addresses>
<Person>
<Name>Mihnea Radulescu</Name>
<Email>mock.email@gmail.com</Email>
</Person>
</Addresses>
</EmailConfiguration>
XML文件的第一部分包含配置文件的XML DTD模式,用户在编写正确的XML内容时可以参考,并且该模式为应用程序提供了检查XML文档有效性的方法。出于安全原因,电子邮件账户的密码不存储在XML文件中。
XML的第二部分是一个为Google邮件账户定制的配置示例。它读取我的电子邮件凭据,并将消息发送给我自己(单个人)。设置为Yahoo!需要用户拥有Yahoo!Mail Plus(付费)账户,因为普通的Yahoo!账户不提供SMTP功能。
C# 实现
.NET提供了适用于电子邮件相关需求的类,这些类位于System.Net
和System.Net.Mail
命名空间下。对于XML内容的读取和解析,则使用了System.Xml
命名空间。
该实现是一个控制台应用程序,依赖于两个类:EmailConfiguration
,用于从XML文件中读取电子邮件配置;以及EmailSender
,用于批量(自动)发送电子邮件。
下面显示了这两个类中两个相关的代码示例。
/* Class EmailConfiguration - parses the XML document using the
.NET SAX API implementation,
retrieving the e-mail configuration data */
private void ParseXMLDocumentWorker(XmlReader xmlReader)
{
bool validName = false, validEmail = false;
string name = string.Empty, email = string.Empty;
try
{
while (xmlReader.Read())
{
switch (xmlReader.NodeType)
{
case XmlNodeType.Element:
switch (xmlReader.LocalName)
{
case "EmailConfiguration":
string enableSSLString =
xmlReader.GetAttribute("EnableSSL");
if (enableSSLString == "true")
enableSSL = true;
else
enableSSL = false;
break;
case "SmtpHost":
smtpHost = xmlReader.ReadString();
break;
case "SmtpPort":
string smtpPortString = xmlReader.ReadString();
smtpPort = int.Parse(smtpPortString);
break;
case "FromAddress":
fromAddress = xmlReader.ReadString();
break;
case "FromName":
fromName = xmlReader.ReadString();
break;
case "Subject":
subject = xmlReader.ReadString();
break;
case "Content":
content = xmlReader.ReadString();
break;
case "Person":
validName = false;
validEmail = false;
break;
case "Name":
name = xmlReader.ReadString();
validName = true;
break;
case "Email":
email = xmlReader.ReadString();
validEmail = true;
break;
}
break;
case XmlNodeType.EndElement:
switch (xmlReader.LocalName)
{
case "Person":
if ((validName == false) || (validEmail == false))
throw new XmlException
("Invalid or incomplete person details.");
else
{
string newAddress = name + " <" + email + ">";
toAddresses.Add(newAddress);
}
break;
}
break;
}
}
}
catch (XmlException)
{
xmlIsValid = false;
Console.Error.WriteLine("The e-mail configuration file is not a
well-formed XML document.");
}
}
// Class EmailSender - sends an email to the specified address
private void SendEmail(string toAddress)
{
try
{
MailAddress mailAddressFrom = new MailAddress(fromAddress, fromName);
MailAddress mailAddressTo = new MailAddress(toAddress);
MailMessage emailMessage = new MailMessage(mailAddressFrom, mailAddressTo);
emailMessage.BodyEncoding = Encoding.UTF8;
emailMessage.IsBodyHtml = false;
emailMessage.Subject = subject;
emailMessage.Body = content;
NetworkCredential emailCredential =
new NetworkCredential(fromAddress, password);
SmtpClient mailClient = new SmtpClient(smtpHost, smtpPort);
mailClient.EnableSsl = enableSSL;
mailClient.UseDefaultCredentials = false;
mailClient.Credentials = emailCredential;
mailClient.Send(emailMessage);
Console.Out.WriteLine("E-mail to " + toAddress + " successfully sent.");
}
catch
{
errorCount++;
Console.Error.WriteLine("Failure sending e-mail to " + toAddress + ".");
}
}
应用价值
该应用程序对于向一群人发送消息非常有用,它允许每个收件人相信电子邮件是专门发给他们的。特别是,节日是这种解决方案证明其价值的时刻,因为需要向许多熟人致以问候。
源代码和应用程序下载
HolidaysMailer
应用程序(一个Google Code项目)的完整源代码可以通过此处访问。如果只对二进制文件感兴趣,可以从此链接下载。
我非常欢迎对这个HolidaysMailer开源(GPL v3)项目的贡献和反馈。
参考文献
- [1] Microsoft Developer Network (MSDN) 页面
历史
- 版本 0.1 - 首次提交 - 2010年3月1日
- 版本 0.2 - 代码更新 - 2010年4月3日
- 版本 0.3 - 更新内容、源代码和二进制文件 - 2011年9月21日
- 版本 0.4 - 从文章和源代码中删除了实际的电子邮件地址,以避免垃圾邮件 - 2013年1月21日