基于Lumisoft.NET组件的POP3邮件接收和删除操作
Lumisoft.NET组件是一个非常强大的邮件发送、邮件接收等功能的开源组件,一般用它来处理邮件的相关操作,是非常合适的。之前也写过一些该组件的随笔文章,不过主要是利用来发送邮件居多,最近由于项目需要,需要利用该组件来接收邮件,邮件通过POP3协议进行接收到本地,故对该组件进行了全面的了解和使用。本文主要是在此背景上,介绍该组件的POP3协议处理类的使用。Lumisoft.NET组件2013年作者有做了一定的更新,修复了一些问题,本文是基于该组件的最新版本进行开发使用。
1、POP3登录及头部信息获取
首先使用POP3,必须创建一个POP3_Client的对象,然后通过Connect和Login进行连接和登录处理,相关的代码如下所示。
using (POP3_Client popClient = new POP3_Client()) { popClient.Logger = new Logger(); popClient.Logger.WriteLog += new EventHandler<WriteLogEventArgs>(WriteLog); popClient.Connect(pop3Server, pop3Port, pop3UseSsl); popClient.Login(username, password);
POP3的的邮件下载通过POP3_Client 对象的属性Messages对象进行,每个POP3_ClientMessage代表一份完整的邮件信息,一开始应该是只是获取一些简单的邮件信息(其中包括邮件的唯一标识UID),这样才能提高POP3协议的处理速度,如下代码所示。
foreach (POP3_ClientMessage message in popClient.Messages)
为了进一步获取邮件头部信息,那么需要进行下面的转换
Mail_Message mime_header = Mail_Message.ParseFromByte(message.HeaderToByte());
转换后Mail_Message承载了邮件头部文件的很多必备信息,如发送人,发送人名称,接收地址,抄送人地址,邮件标题,邮件日期等等信息。
这些邮件地址的信息,都是通过Mail_t_Mailbox对象来记录,一般包含邮件地址的Address和显示名称DisplayName,这样非常方便用来显示,如我们可以进行转义,记录到数据库里面。
if (mime_header.From != null) { //伍华聪(wuhuacong@163.com) string displayname = mime_header.From[0].DisplayName; string from = mime_header.From[0].Address;// DecodeString(mime_header.From[0].Address); if (!string.IsNullOrEmpty(displayname)) { info.From = string.Format("{0}({1})", displayname, from); } else { info.From = string.Format("{0}", from); } }
if (mime_header.To != null) { StringBuilder sb = new StringBuilder(); foreach (Mail_t_Mailbox recipient in mime_header.To.Mailboxes) { string displayname = recipient.DisplayName; string address = recipient.Address; if (!string.IsNullOrEmpty(displayname)) { sb.AppendFormat("{0}({1});", displayname, address); } else { sb.AppendFormat("{0};", address); } } info.Senders = sb.ToString().Trim(';'); } if (mime_header.Cc != null) { StringBuilder sb = new StringBuilder(); foreach (Mail_t_Mailbox recipient in mime_header.Cc.Mailboxes) { string displayname = recipient.DisplayName; string address = recipient.Address; if (!string.IsNullOrEmpty(displayname)) { sb.AppendFormat("{0}({1});", displayname, address); } else { sb.AppendFormat("{0};", address); } } info.Carboncopy = sb.ToString().Trim(';'); }
每封Email会有一个在Pop3服务器范围内唯一的Id,检查这个Id是否存在就可以知道以前有没有接收过这封邮件
info.MailUid = message.UID;
每份邮件的头部信息,都会包含一个日期的,如下可以获取到该日期
info.Date = mime_header.Date;
标题信息可以通过下面代码获取
info.Title = mime_header.Subject;/
2、邮件正文信息和附件信息的获取
如果需要进一步获取邮件的正文内容,则需要对信息进行进一步的转换,把message对象进行MessageToByte操作,然后利用函数Mail_Message.ParseFromByte进行转换。
byte[] messageBytes = message.MessageToByte(); Mail_Message mime_message = Mail_Message.ParseFromByte(messageBytes); if (mime_message == null) continue;
info.Body = mime_message.BodyText; try { if (!string.IsNullOrEmpty(mime_message.BodyHtmlText)) { info.Body = mime_message.BodyHtmlText; } } catch { //屏蔽编码出现错误的问题,错误在BodyText存在而BodyHtmlText不存在的时候,访问BodyHtmlText会出现 }
邮件的附件是通过MIME_Entity来承载信息的,所以我们需要把对象通过mime_message.GetAttachments(true, true)进行获取,转换为附件信息。
#region 邮件附件内容 foreach (MIME_Entity entity in mime_message.GetAttachments(true, true)) { if (entity.ContentDisposition != null && entity.ContentDisposition.Param_FileName != null) { //Console.WriteLine("Attachment: " + entity.ContentDisposition.Param_FileName); string fileName = entity.ContentDisposition.Param_FileName;
如果需要进一步获取附件里面的文件字节流,那么还需要进行进一步的转换为MIME_b_SinglepartBase对象。
MIME_b_SinglepartBase byteObj = (MIME_b_SinglepartBase)entity.Body; if (byteObj != null) { FileUtil.CreateFile(filePath, byteObj.Data); fileSize = byteObj.Data.Length;
如果要区分邮件里面的附件是内嵌图片附件还是真正的附件,那么可以通过下面代码进行判断,如果是MIME_DispositionTypes.Attachment的就是普通附件,MIME_DispositionTypes.Inline的就是内嵌正文的附件。
entity.ContentDisposition.DispositionType == MIME_DispositionTypes.Attachment
3、邮件的删除操作
服务器上的邮件,可以通过POP3的协议方式进行删除,删除操作很简单,主要是通过mail.MarkForDeletion进行标识即可,实例操作代码如下所示
using (POP3_Client c = new POP3_Client()) { c.Connect(pop3Server, pop3Port, pop3UseSsl); c.Login(username, password); if (c.Messages.Count > 0) { foreach (POP3_ClientMessage mail in c.Messages) { try { if (toDeleteMailUidList.Contains(mail.UID)) { mail.MarkForDeletion(); deletedList.Add(mail.UID); } } catch (Exception ex) { LogTextHelper.Error(ex); } } } }
专注于Winform开发框架、WCF开发框架的研究及应用。
转载请注明出处:
撰写人:伍华聪 http://www.iqidi.com
基于Lumisoft.NET组件和.NET API实现邮件发送功能的对比
我在较早时期的一篇文章《基于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"); }
专注于Winform开发框架、WCF开发框架的研究及应用。
转载请注明出处:
撰写人:伍华聪 http://www.iqidi.com
基于Lumisoft.NET组件开发碰到乱码等一些问题的解决
在Lumisoft.NET组件获取POP3邮件的时候,发现大多数邮件都能正常获取,不过对于一些特殊的邮件,好像总是会出现转换错误,或者出现乱码及部分乱码现象,有些在标题里面或者邮件接收人地址,而有些则在内容里面,为了更好整理相关的问题,写了本文,希望对大家使用该组件有一定的帮助作用。
1、 日期转换出错问题。
错误信息:[2013-05-04 10:49:03] 转换邮件的Date出错:账号wuhuacong@163.com 邮件标题:ICP???????????????????????wuhuacong)
LumiSoft.Net.ParseException: Header field 'Date' parsing failed.
在 LumiSoft.Net.Mail.Mail_Message.get_Date()
在 WHC.PlugInService.Pop3Helper.Receive() 位置 ......\Pop3Helper.cs:行号 160
错误原因:由于邮件格式的日期内容格式不同,导致无法正常解析。如一般的格式为下面
Message-ID: <d74841c5887b4df692ebdb7ec7802054@4782e72954a24cc89535840ea2e5da5b> Date: Fri, 26 Apr 2013 08:56:52 GMT Mime-Version: 1.0 From: "wuhuacong2013@163.com" <wuhuacong2013@163.com> To: "wuhuacong@96900.com.cn" <wuhuacong@96900.com.cn>
有些邮件日期格式是2013-05-06 19:01:44,则Lumisoft组件无法解析,需要跟踪到他的邮件日期处理的代码,然后进行修改才可以实现正常的邮件日期解析了。
官方的代码如下所示。
public DateTime Date { get{ if(this.IsDisposed){ throw new ObjectDisposedException(this.GetType().Name); } MIME_h h = this.Header.GetFirst("Date"); if(h != null){ try{ return MIME_Utils.ParseRfc2822DateTime(((MIME_h_Unstructured)h).Value); } catch{ throw new ParseException("Header field 'Date' parsing failed."); } } else{ return DateTime.MinValue; } } set{ if(this.IsDisposed){ throw new ObjectDisposedException(this.GetType().Name); } if(value == DateTime.MinValue){ this.Header.RemoveAll("Date"); } else{ MIME_h h = this.Header.GetFirst("Date"); if(h == null){ this.Header.Add(new MIME_h_Unstructured("Date",MIME_Utils.DateTimeToRfc2822(value))); } else{ this.Header.ReplaceFirst(new MIME_h_Unstructured("Date",MIME_Utils.DateTimeToRfc2822(value))); } } } }
需要增加对普通日期格式的修改,修改后的代码如下所示
public DateTime Date { get{ if(this.IsDisposed){ throw new ObjectDisposedException(this.GetType().Name); } MIME_h h = this.Header.GetFirst("Date"); if(h != null){ try{ return MIME_Utils.ParseRfc2822DateTime(((MIME_h_Unstructured)h).Value); } catch{ //尝试转换正常的日期 DateTime dt; string dateString = ((MIME_h_Unstructured)h).Value; bool success = DateTime.TryParse(dateString, out dt); if (success) { return dt; } else { throw new ParseException("Header field 'Date' parsing failed."); } } } else{ return DateTime.MinValue; } } set{ if(this.IsDisposed){ throw new ObjectDisposedException(this.GetType().Name); } if(value == DateTime.MinValue){ this.Header.RemoveAll("Date"); } else{ MIME_h h = this.Header.GetFirst("Date"); if(h == null){ this.Header.Add(new MIME_h_Unstructured("Date",MIME_Utils.DateTimeToRfc2822(value))); } else{ this.Header.ReplaceFirst(new MIME_h_Unstructured("Date",MIME_Utils.DateTimeToRfc2822(value))); } } } }
2、由于意外的数据包格式,握手失败
错误信息:[2013-05-04 10:13:54] System.IO.IOException: 由于意外的数据包格式,握手失败。
在 LumiSoft.Net.TCP.TCP_Client.Connect(String host, Int32 port, Boolean ssl)
在 WHC.PlugInService.SmtpHelper.Send() 位置 ........\SmtpHelper.cs:行号 123
在 WHC.PlugInService.SendMailService.DataThreadHandle(MailSendConfigInfo info) 位置 ...............\SendMailService.cs:行号 66
错误原因:由于POP3的配置端口不正确导致,一般的端口必须严格按照正常的来填写。
邮件SMTP和POP3常用配置说明:
邮箱 |
Smtp服务器 |
Smtp端口 |
POP3服务器 |
POP3端口 |
使用SSL |
Gmail.com |
smtp.gmail.com |
465 |
pop.gmail.com |
995 |
true |
QQ.com |
smtp.qq.com |
25 |
pop.qq.com |
110 |
true |
163.com |
smtp.163.com |
25 |
pop.163.com |
110 |
false |
Sina.com |
smtp.sina.com |
25 |
pop.sina.com |
110 |
false |
其他 |
smtp.test.com |
25 |
pop.test.com |
110 |
false |
3、邮件标题乱码问题
错误信息:标题出现类似=?utf-8?B?5rWL6K+V6YKu5Lu2?=
错误原因:这个是因为编码的问题,其中=?utf-8?B是表示该段字符为UTF-8的格式,后面的是base64格式的内容。除了utf-8,还可以出现gb2312或者ibm-euccn等格式。为了转换上面的编码问题,我写了一个转码函数,如下所示。
private string DecodeString(string input) { string regex = @"=\?(?<encode>.*?)\?B\?(?<body>.*?)\?="; Regex re = new Regex(regex, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline); MatchCollection mcs = re.Matches(input); foreach (Match mc in mcs) { string encode = mc.Groups["encode"].Value; if (!string.IsNullOrEmpty(encode)) { if (encode.ToLower().Contains("euccn") || encode.ToLower().Contains("euc-cn") || encode.ToLower().Contains("gbk")) { encode = "gb2312"; } else if (encode.ToLower().Contains("utf8")) { encode = "utf-8"; } string body = mc.Groups["body"].Value; byte[] bytes = Convert.FromBase64String(body); string result = Encoding.GetEncoding(encode).GetString(bytes); input = input.Replace(mc.Value, result); } } return input; }
如可以通过代码吧标题进行转码解析
info.Title = DecodeString(mime_header.Subject);
转码后,标题和相关的内容都可以正常显示了。
除了上面的转码操作,还有一种更好的方法,能够使得邮件相关信息正常显示。
因为通过分析了解到,由于Lumisoft的Mail_Message.ParseFromByte函数默认只是以UTF8转换字节,一旦字节为GB2312格式,就会发生转换乱码问题,因此先经过Default编码转换,然后再以UTF8获取字节,即可正常转换邮件头部。
byte[] utf8Bytes = Encoding.UTF8.GetBytes(message.HeaderToString()); Mail_Message mime_header = Mail_Message.ParseFromByte(utf8Bytes);
这样获取到的标题,以及邮件头部等信息,都是正常的了。
专注于Winform开发框架、WCF开发框架的研究及应用。
转载请注明出处:
撰写人:伍华聪 http://www.iqidi.com