我在較早時期的一篇文章《基於Lumisoft.NET實現的郵件發送功能》有大致對這個Lumisoft.NET組件的使用進行了介紹,在《DevExpress控件使用之RichEditControl的使用》則對使用.NET API進行郵件發送進行了說明,其實,實現郵件發送,這兩種方式是比較常見的,當然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; }
綜合以上兩者的發送功能,都可以實現郵件的發送操作,如下界面是發送郵件界面。
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"); }