深入Lumisoft.NET组件与.NET API实现邮件发送功能的对比分析

  我在另一篇文章《深入Lumisoft.NET实现邮件发送功能的方法详解》有大致对这个Lumisoft.NET组件的使用进行了介绍,当然Lumisoft.NET组件除了提供邮件发送功能外,还提供了邮件接收等功能的处理(包括基于POP3协议和IMAP协议),而.NET则除了提供SMTP协议功能外,则没有提供POP3协议处理的相关类库,因此收取邮件这需要自己进行封装(需要也可以参考codeproject.com上的相关文章)。

  1、.NET的邮件发送功能实现

  .NET本身封装了一个SmtpClient类以及相关的邮件对象类,这样利用这些类库,也可以方便实现邮件的发送功能的了。

  如添加发送人地址,抄送地址,以及暗送地址(多个地址用逗号分开)代码如下。

  

复制代码 代码如下:

  string toEmails = mailInfo.ToEmail;

  string bcc = "";

  mailInfo.RecipientBCC.ForEach(obj => bcc += string.Format("{0},", obj));

  bcc = bcc.Trim(',');

  string cc = "";

  mailInfo.RecipientCC.ForEach(obj => cc += string.Format("{0},", obj));

  cc = cc.Trim(',');

  MailMessage mail = new MailMessage(settingInfo.MailFrom, toEmails);

  if (!string.IsNullOrEmpty(bcc))

  {

  mail.Bcc.Add(bcc);

  }

  if (!string.IsNullOrEmpty(cc))

  {

  mail.CC.Add(cc);

  }

  .NET的附件和嵌入式资源由对象Attachment和LinkedResource进行管理,他们的利用代码如下所示:

  

复制代码 代码如下:

  //附件

  foreach (string fileName in mailInfo.Attachments)

  {

  mail.Attachments.Add(new Attachment(fileName));

  }

  //嵌入资源

  AlternateView view = AlternateView.CreateAlternateViewFromString(mailInfo.Body, Encoding.UTF8, MediaTypeNames.Text.Html);

  foreach (LinkedAttachementInfo link in mailInfo.EmbedObjects)

  {

  LinkedResource resource = new LinkedResource(link.Stream, link.MimeType);

  resource.ContentId = link.ContentId;

  view.LinkedResources.Add(resource);

  }

  mail.AlternateViews.Add(view);

  发送邮件的其他部分代码如下所示

  

复制代码 代码如下:

  mail.IsBodyHtml = mailInfo.IsBodyHtml;

  mail.BodyEncoding = Encoding.UTF8;

  mail.Subject = mailInfo.Subject;

  mail.SubjectEncoding = Encoding.UTF8;

  //发送账户设置信息

  SmtpClient client = new SmtpClient();

  client.Host = settingInfo.SmtpServer;

  client.Port = settingInfo.SmptPort;

  client.UseDefaultCredentials = false;

  client.DeliveryMethod = SmtpDeliveryMethod.Network;

  client.Credentials = new NetworkCredential(settingInfo.SmtpUser, settingInfo.SmtpPass);

  bool success = false;

  try

  {

  client.Send(mail);

  success = true;

  }

  catch (Exception ex)

  {

  LogTextHelper.Error(ex);

  //throw;

  }

  上面利用.net的SmtpClient发送邮件操作的完整代码如下:

  

复制代码 代码如下:

  /// <summary>

  /// 发送外部邮件(系统配置,系统邮件)

  /// </summary>

  /// <param name="mailInfo">发送邮件信息</param>

  /// <returns></returns>

  public CommonResult Send(MailInfo mailInfo)

  {

  CommonResult result = new CommonResult();

  try

  {

  AppConfig config = new AppConfig();

  string MailDomain = config.AppConfigGet("MailDomain");

  string MailUsername = config.AppConfigGet("MailUsername");

  string MailPassword = config.AppConfigGet("MailPassword");

  string MailPort = config.AppConfigGet("MailPort");

  string MailFrom = config.AppConfigGet("MailFrom");

  int port = 25;

  int.TryParse(MailPort, out port);

  SmtpSettingInfo settingInfo = new SmtpSettingInfo(MailDomain, port,

  MailUsername, MailPassword, MailFrom);

  result.Success = PrivateSendEmail(mailInfo, settingInfo);

  }

  catch (Exception ex)

  {

  result.ErrorMessage = ex.Message;

  throw;

  }

  return result;

  }

  /// <summary>

  /// 通用发送邮件操作

  /// </summary>

  private static bool PrivateSendEmail(MailInfo mailInfo, SmtpSettingInfo settingInfo)

  {

  string toEmails = mailInfo.ToEmail;

  string bcc = "";

  mailInfo.RecipientBCC.ForEach(obj => bcc += string.Format("{0},", obj));

  bcc = bcc.Trim(',');

  string cc = "";

  mailInfo.RecipientCC.ForEach(obj => cc += string.Format("{0},", obj));

  cc = cc.Trim(',');

  MailMessage mail = new MailMessage(settingInfo.MailFrom, toEmails);

  if (!string.IsNullOrEmpty(bcc))

  {

  mail.Bcc.Add(bcc);

  }

  if (!string.IsNullOrEmpty(cc))

  {

  mail.CC.Add(cc);

  }

  //附件

  foreach (string fileName in mailInfo.Attachments)

  {

  mail.Attachments.Add(new Attachment(fileName));

  }

  //嵌入资源

  AlternateView view = AlternateView.CreateAlternateViewFromString(mailInfo.Body, Encoding.UTF8, MediaTypeNames.Text.Html);

  foreach (LinkedAttachementInfo link in mailInfo.EmbedObjects)

  {

  LinkedResource resource = new LinkedResource(link.Stream, link.MimeType);

  resource.ContentId = link.ContentId;

  view.LinkedResources.Add(resource);

  }

  mail.AlternateViews.Add(view);

  mail.IsBodyHtml = mailInfo.IsBodyHtml;

  mail.BodyEncoding = Encoding.UTF8;

  mail.Subject = mailInfo.Subject;

  mail.SubjectEncoding = Encoding.UTF8;

  //发送账户设置信息

  SmtpClient client = new SmtpClient();

  client.Host = settingInfo.SmtpServer;

  client.Port = settingInfo.SmptPort;

  client.UseDefaultCredentials = false;

  client.DeliveryMethod = SmtpDeliveryMethod.Network;

  client.Credentials = new NetworkCredential(settingInfo.SmtpUser, settingInfo.SmtpPass);

  bool success = false;

  try

  {

  client.Send(mail);

  success = true;

  }

  catch (Exception ex)

  {

  LogTextHelper.Error(ex);

  //throw;

  }

  string message = string.Format("发送给【{0}】的邮件“{1}”,{2},时间:{3}",

  mailInfo.ToEmail[0], mailInfo.Subject, success ? "发送成功" : "发送失败", DateTime.Now);

  LogTextHelper.Info(message);

  return success;

  }

  2、基于Lumisoft.NET组件的邮件发送功能实现

  基于Lumisoft.NET组件的邮件发送,也是一种很常用的,因为这个开源组件非常强大,经常可以在一些程序中被使用。

  这个发送邮件的功能主要是利用SMTP_Client类来实现的,如下代码所示。注意其中的Authenticate函数已经被舍弃,可以使用Auth方法进行验证。但是函数参数有所不同,根据验证对象,使用不同的验证方式,一般选择AUTH_SASL_Client_Plain对象即可。

  

复制代码 代码如下:

  public bool Send()

  {

  bool sended = false;

  using (SMTP_Client client = new SMTP_Client())

  {

  client.Connect(smtpServer, smtpPort, smtpUseSsl);

  client.EhloHelo(smtpServer);

  var authhh = new AUTH_SASL_Client_Plain(username, password);

  client.Auth(authhh);

  //client.Authenticate(username, password);

  //string text = client.GreetingText;

  client.MailFrom(from, -1);

  foreach (string address in toList.Keys)

  {

  client.RcptTo(address);

  }

  //采用Mail_Message类型的Stream

  Mail_Message m = Create_PlainText_Html_Attachment_Image(toList, ccList, from, fromDisplay, subject, body, attachments);

  using (MemoryStream stream = new MemoryStream())

  {

  m.ToStream(stream, new MIME_Encoding_EncodedWord(MIME_EncodedWordEncoding.Q, Encoding.UTF8), Encoding.UTF8);

  stream.Position = 0;

  client.SendMessage(stream);

  sended = true;

  }

  if (m != null)

  {

  m.Dispose();

  }

  client.Disconnect();

  }

  return sended;

  }

  构造用于SMTP发送的数据,可以使用Mail_Message 对象,也可以使用Mime对象,虽然读都可以实现发送功能,不过Mime对象是舍弃的对象了。

  构造Mail_Message对象后,创建用于发送的格式要转换为Stream对象。转换为发送的Stream操作如下所示。

  

复制代码 代码如下:

  using (MemoryStream stream = new MemoryStream())

  {

  m.ToStream(stream, new MIME_Encoding_EncodedWord(MIME_EncodedWordEncoding.Q, Encoding.UTF8), Encoding.UTF8);

  stream.Position = 0;

  client.SendMessage(stream);

  sended = true;

  }

  构造Mail_Message格式的邮件操作如下所示。

  

复制代码 代码如下:

  private Mail_Message Create_PlainText_Html_Attachment_Image(Dictionary<string,string> tomails, Dictionary<string, string> ccmails, string mailFrom, string mailFromDisplay,

  string subject, string body, Dictionary<string, string> attachments, string notifyEmail = "", string plaintTextTips = "")

  {

  Mail_Message msg = new Mail_Message();

  msg.MimeVersion = "1.0";

  msg.MessageID = MIME_Utils.CreateMessageID();

  msg.Date = DateTime.Now;

  msg.Subject = subject;

  msg.From = new Mail_t_MailboxList();

  msg.From.Add(new Mail_t_Mailbox(mailFromDisplay, mailFrom));

  msg.To = new Mail_t_AddressList();

  foreach (string address in tomails.Keys)

  {

  string displayName = tomails[address];

  msg.To.Add(new Mail_t_Mailbox(displayName, address));

  }

  msg.Cc = new Mail_t_AddressList();

  foreach (string address in ccmails.Keys)

  {

  string displayName = ccmails[address];

  msg.Cc.Add(new Mail_t_Mailbox(displayName, address));

  }           

  //设置回执通知

  if (!string.IsNullOrEmpty(notifyEmail) && ValidateUtil.IsEmail(notifyEmail))

  {

  msg.DispositionNotificationTo.Add(new Mail_t_Mailbox(notifyEmail, notifyEmail));

  }

  #region MyRegion

  //--- multipart/mixed -----------------------------------

  MIME_h_ContentType contentType_multipartMixed = new MIME_h_ContentType(MIME_MediaTypes.Multipart.mixed);

  contentType_multipartMixed.Param_Boundary = Guid.NewGuid().ToString().Replace('-', '.');

  MIME_b_MultipartMixed multipartMixed = new MIME_b_MultipartMixed(contentType_multipartMixed);

  msg.Body = multipartMixed;

  //--- multipart/alternative -----------------------------

  MIME_Entity entity_multipartAlternative = new MIME_Entity();

  MIME_h_ContentType contentType_multipartAlternative = new MIME_h_ContentType(MIME_MediaTypes.Multipart.alternative);

  contentType_multipartAlternative.Param_Boundary = Guid.NewGuid().ToString().Replace('-', '.');

  MIME_b_MultipartAlternative multipartAlternative = new MIME_b_MultipartAlternative(contentType_multipartAlternative);

  entity_multipartAlternative.Body = multipartAlternative;

  multipartMixed.BodyParts.Add(entity_multipartAlternative);

  //--- text/plain ----------------------------------------

  MIME_Entity entity_text_plain = new MIME_Entity();

  MIME_b_Text text_plain = new MIME_b_Text(MIME_MediaTypes.Text.plain);

  entity_text_plain.Body = text_plain;

  //普通文本邮件内容,如果对方的收件客户端不支持HTML,这是必需的

  string plainTextBody = "如果你邮件客户端不支持HTML格式,或者你切换到“普通文本”视图,将看到此内容";

  if (!string.IsNullOrEmpty(plaintTextTips))

  {

  plainTextBody = plaintTextTips;

  }

  text_plain.SetText(MIME_TransferEncodings.QuotedPrintable, Encoding.UTF8, plainTextBody);

  multipartAlternative.BodyParts.Add(entity_text_plain);

  //--- text/html -----------------------------------------

  string htmlText = body;//"<html>这是一份测试邮件,<img src=\"cid:test.jpg\">来自<font color=red><b>LumiSoft.Net</b></font></html>";

  MIME_Entity entity_text_html = new MIME_Entity();

  MIME_b_Text text_html = new MIME_b_Text(MIME_MediaTypes.Text.html);

  entity_text_html.Body = text_html;

  text_html.SetText(MIME_TransferEncodings.QuotedPrintable, Encoding.UTF8, htmlText);

  multipartAlternative.BodyParts.Add(entity_text_html);

  //--- application/octet-stream -------------------------

  WebClient client = new WebClient();

  foreach (string attach in attachments.Keys)

  {

  try

  {

  byte[] bytes = client.DownloadData(attach);

  using (MemoryStream stream = new MemoryStream(bytes))

  {

  multipartMixed.BodyParts.Add(Mail_Message.CreateAttachment(stream, attachments[attach]));

  }

  }

  catch (Exception ex)

  {

  LogTextHelper.Error(ex);

  }

  }

  #endregion

  return msg;

  }

  而构造Mime格式的操作如下所示。

  

复制代码 代码如下:

  private Mime Create_Html_Attachment_Image(string mailTo, string mailFrom, string mailFromDisplay,

  string subject, string body, List<string> attachments, Dictionary<string, string> embedImages, string notifyEmail = "", string plaintTextTips = "",

  string replyEmail = "")

  {

  Mime m = new Mime();

  MimeEntity mainEntity = m.MainEntity;

  mainEntity.From = new AddressList();

  mainEntity.From.Add(new MailboxAddress(mailFromDisplay, mailFrom));

  mainEntity.To = new AddressList();

  mainEntity.To.Add(new MailboxAddress(mailTo, mailTo));

  mainEntity.Subject = subject;

  mainEntity.ContentType = MediaType_enum.Multipart_mixed;

  //设置回执通知

  if (!string.IsNullOrEmpty(notifyEmail) && ValidateUtil.IsEmail(notifyEmail))

  {

  mainEntity.DSN = notifyEmail;

  }

  //设置统一回复地址

  if (!string.IsNullOrEmpty(replyEmail) && ValidateUtil.IsEmail(replyEmail))

  {

  mainEntity.ReplyTo = new AddressList();

  mainEntity.ReplyTo.Add(new MailboxAddress(replyEmail, replyEmail));

  }

  MimeEntity textEntity = mainEntity.ChildEntities.Add();

  textEntity.ContentType = MediaType_enum.Text_html;

  textEntity.ContentTransferEncoding = ContentTransferEncoding_enum.QuotedPrintable;

  textEntity.DataText = body;

  //附件

  foreach (string attach in attachments)

  {

  MimeEntity attachmentEntity = mainEntity.ChildEntities.Add();

  attachmentEntity.ContentType = MediaType_enum.Application_octet_stream;

  attachmentEntity.ContentDisposition = ContentDisposition_enum.Attachment;

  attachmentEntity.ContentTransferEncoding = ContentTransferEncoding_enum.Base64;

  FileInfo file = new FileInfo(attach);

  attachmentEntity.ContentDisposition_FileName = file.Name;

  attachmentEntity.DataFromFile(attach);

  }

  //嵌入图片

  foreach (string key in embedImages.Keys)

  {

  MimeEntity attachmentEntity = mainEntity.ChildEntities.Add();

  attachmentEntity.ContentType = MediaType_enum.Application_octet_stream;

  attachmentEntity.ContentDisposition = ContentDisposition_enum.Inline;

  attachmentEntity.ContentTransferEncoding = ContentTransferEncoding_enum.Base64;

  string imageFile = embedImages[key];

  FileInfo file = new FileInfo(imageFile);

  attachmentEntity.ContentDisposition_FileName = file.Name;

  //string displayName = Path.GetFileNameWithoutExtension(fileName);

  attachmentEntity.ContentID = key;//BytesTools.BytesToHex(Encoding.Default.GetBytes(fileName));

  attachmentEntity.DataFromFile(imageFile);

  }

  return m;

  }

  综合以上两者的发送功能,都可以实现邮件的发送操作,如下界面是发送邮件界面。

  

深入Lumisoft.NET组件与.NET API实现邮件发送功能的对比分析

  3、LumiSoft.NET存储eml邮件文件以及发送eml文件操作

  除了上面的发送普通邮件,Lumisoft还支持吧邮件序列号存储到文件(.eml邮件文件)里面,然后也可以通过把文件读取到流里面,进行发送,对于某种场合,可以把邮件存储到eml文件是一个很好的操作。

  存储EML文件的相关操作如下所示。

  

复制代码 代码如下:

  private void btnCreateFile_Click(object sender, EventArgs e)

  {

  string attachFile = Path.Combine(Application.StartupPath, "Attachment/Hotel2.png");

  List<string> attachments = new List<string>();

  attachments.Add(attachFile);

  string subject = "测试邮件";

  string body = "<html>这是一份测试邮件,来自<font color=red><b>LumiSoft.Net</b></font></html>";

  string bodyEmbedy = "<html>这是一份测试邮件<img src=\"cid:test.jpg\">,来自<font color=red><b>LumiSoft.Net</b></font></html>";

  Dictionary<string, string> embedList = new Dictionary<string, string>();

  embedList.Add("test.jpg", "C:\\test.jpg");

  //存储为Eml文件

  string path = Path.Combine(Application.StartupPath, "Eml");

  DirectoryUtil.AssertDirExist(path);

  string emlFile = string.Format("{0}/{1}.eml", path, DateTime.Now.ToFileTime());

  Mime m = Create_Html_Attachment_Image(to, from, from, subject, bodyEmbedy, attachments, embedList);

  m.ToFile(emlFile);

  MessageUtil.ShowTips("OK");

  }

  发送EML文件操作如下所示。

  

复制代码 代码如下:

  private void btnSendFile_Click(object sender, EventArgs e)

  {

  using (SMTP_Client client = new SMTP_Client())

  {

  int smtpPort = smtpUseSsl ? WellKnownPorts.SMTP_SSL : WellKnownPorts.SMTP;

  client.Connect(smtpServer, smtpPort, smtpUseSsl);

  client.EhloHelo(smtpServer);

  //var authhh = new AUTH_SASL_Client_Plain(username, password);

  //client.Auth(authhh);

  client.Authenticate(username, password);

  //string text = client.GreetingText;

  client.MailFrom(from, -1);

  client.RcptTo(to);

  string path = Path.Combine(Application.StartupPath, "Eml");

  string emlFile = Directory.GetFiles(path)[0];

  var msg = Mail_Message.ParseFromFile(emlFile);

  MemoryStream stream = new MemoryStream();

  msg.ToStream(stream, new MIME_Encoding_EncodedWord(MIME_EncodedWordEncoding.Q, Encoding.UTF8), Encoding.UTF8);

  stream.Position = 0;

  client.SendMessage(stream);

  client.Disconnect();

  }

  MessageUtil.ShowTips("OK");

  }