基于Lumisoft.NET组件的POP3邮件接收和删除操作

基于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);
                        }
                    }
                }
            }
复制代码
主要研究技术:代码生成工具、Visio二次开发、送水管理软件等共享软件开发
专注于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");
        }
复制代码
主要研究技术:代码生成工具、Visio二次开发、送水管理软件等共享软件开发
专注于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);

这样获取到的标题,以及邮件头部等信息,都是正常的了。

主要研究技术:代码生成工具、Visio二次开发、送水管理软件等共享软件开发
专注于Winform开发框架、WCF开发框架的研究及应用。
  转载请注明出处:
撰写人:伍华聪  http://www.iqidi.com 
    
 
 
标签: 开发辅助
原文地址:https://www.cnblogs.com/Leo_wl/p/3063953.html