如何比OpenPop.dll更快地解析电子邮件

use*_*592 1 .net c# email parsing pop3

可以使用OpenPop.dll.

    Pop3Client objPOP3Client = new Pop3Client();
    int intTotalEmail = 0;
    DataTable dtEmail = new DataTable();
    object[] objMessageParts;

    try
    {
        dtEmail = GetAllEmailStructure();

        if (objPOP3Client.Connected)
            objPOP3Client.Disconnect();

        objPOP3Client.Connect(strHostName, intPort, bulUseSSL);
        try
        {
            objPOP3Client.Authenticate(strUserName, new Common()._Decode(strPassword));
            intTotalEmail = objPOP3Client.GetMessageCount();

            AddMapping();

            for (int i = 1; i <= intTotalEmail; i++)
            {
                objMessageParts = GetMessageContent(i, ref objPOP3Client, dtExistMailList);

                if (objMessageParts != null && objMessageParts[0].ToString() == "0")
                {
                    AddToDtEmail(objMessageParts, i, dtEmail, dtUserList, dtTicketIDList, dtBlacklistEmails, dtBlacklistSubject, dtBlacklistDomains);
                }
            }
        }
        catch (Exception ex)
        {
        }
    }
    catch (Exception ex)
    {
        ParserLogError(ex, "GetAllEmail()");
    }
    finally
    {
        if (objPOP3Client.Connected)
            objPOP3Client.Disconnect();
    }

    // function

     public object[] GetMessageContent(int intMessageNumber, ref Pop3Client objPOP3Client, DataTable dtExistingMails)
  {
    object[] strArrMessage = new object[10];
    Message objMessage;
    MessagePart plainTextPart = null, HTMLTextPart = null;
    string strMessageId = "";

    try
    {
        strArrMessage[0] = "";
        strArrMessage[1] = "";
        strArrMessage[2] = "";
        strArrMessage[3] = "";
        strArrMessage[4] = "";
        strArrMessage[5] = "";
        strArrMessage[6] = "";
        strArrMessage[7] = null;
        strArrMessage[8] = null;
        strArrMessage[7] = "";
        strArrMessage[8] = "";

        objMessage = objPOP3Client.GetMessage(intMessageNumber);
        strMessageId = (objMessage.Headers.MessageId == null ? "" : objMessage.Headers.MessageId.Trim());

        if (!IsExistMessageID(dtExistingMails, strMessageId)) //check in data base message id is exists or not 
        {
            strArrMessage[0] = "0";
            strArrMessage[1] = objMessage.Headers.From.Address.Trim();     // From EMail Address
            strArrMessage[2] = objMessage.Headers.From.DisplayName.Trim(); // From EMail Name
            strArrMessage[3] = objMessage.Headers.Subject.Trim();// Mail Subject     
            plainTextPart = objMessage.FindFirstPlainTextVersion();
            strArrMessage[4] = (plainTextPart == null ? "" : plainTextPart.GetBodyAsText().Trim());
            HTMLTextPart = objMessage.FindFirstHtmlVersion();
            strArrMessage[5] = (HTMLTextPart == null ? "" : HTMLTextPart.GetBodyAsText().Trim());
            strArrMessage[6] = strMessageId;
            List<MessagePart> attachment = objMessage.FindAllAttachments();
            strArrMessage[7] = null;
            strArrMessage[8] = null;
            if (attachment.Count > 0)
            {
                if (attachment[0] != null && attachment[0].IsAttachment)
                {
                    strArrMessage[7] = attachment[0].FileName.Trim();
                    strArrMessage[8] = attachment[0];
                }
            }
        }
        else
        {
            strArrMessage[0] = "1";
        }
    }
    catch (Exception ex)
    {
        ParserLogError(ex, "GetMessageContent()");
    }
    return strArrMessage;
 }
Run Code Online (Sandbox Code Playgroud)

但是,我想让它比OpenPop.dll更快.所以如果有任何其他技术可以解析邮件,请告诉我.

请检查代码,然后告诉我.

提前致谢

jst*_*ast 6

但是,我想让它比OpenPop.dll更快.所以如果有任何其他技术可以解析邮件,请告诉我.

在你的GetMessageContent()方法中,占用大量时间的1个地方是:

objMessage = objPOP3Client.GetMessage(intMessageNumber);
Run Code Online (Sandbox Code Playgroud)

下载消息的网络I/O部分无法真正优化,但OpenPop.NET的解析器速度很慢(基于我自己的性能测试).

MimeKit是在解析电子邮件比OpenPop.NET快25倍.

OpenPop.NET的MIME解析器中的一个主要性能问题是它使用StreamReader进行解析(由于不必要的字符集转换很慢,一次读取1行等等 - 我对另一个电子邮件库的分析使用StreamReader进行解析:https://stackoverflow.com/a/18787176/87117).

然后就是问题,OpenPop.NET的解析器在解析/解码之前还使用Regex从头字符串中删除CFWS(注释和折叠空格).这很贵.编写一个可以处理CFWS的好的标记器会好得多.

如果您对我用来优化MimeKit的其他一些技术感兴趣(比高度优化的C实现快或快),我写了一些关于此的博客文章:

MimeKit使用的优化技巧:第1部分

我在第1部分中讨论的优化摘要是替换这样的循环,扫描行的结尾:

while (*inptr != (byte) '\n')
    inptr++;
Run Code Online (Sandbox Code Playgroud)

使用更快的循环,如下所示:

int* dword = (int*) inptr;

do {
    mask = *dword++ ^ 0x0A0A0A0A;
    mask = ((mask - 0x01010101) & (~mask & 0x80808080));
} while (mask == 0);

inptr = (byte*) (dword - 1);
while (*inptr != (byte) '\n')
    inptr++;
Run Code Online (Sandbox Code Playgroud)

它将性能提高了20%(尽管在非x86架构上,它需要'dword'为4字节对齐).

MimeKit使用的优化技巧:第2部分

在第2部分中,我将讨论编写System.IO.MemoryStream的更优化版本.MemoryStream的问题在于它必须在内容中保留1个连续的内存块,这意味着当您向其写入更多数据并且必须调整其内部字节数组的大小时,它必须将内容复制到新数组(这是昂贵的,特别是一旦流中的数据量很大).

为了解决这个性能瓶颈,我编写了一个MemoryBlockStream,它不需要使用连续的内存块 - 它使用字节数组的链接列表.当你溢出当前缓冲区时,它不必重新调整字节数组的大小,而是简单地分配另一个2048字节的数组,数据将溢出并将其附加到链表中.

注意:MimeKit本身只进行电子邮件解析,它不执行POP3或SMTP或IMAP.如果你想要那种功能,我还写了一个基于MimeKit构建的库,它也是这样做的:MailKit

更新:

使用MailKit(根据要求)下载/解析所有消息的示例代码:

using System;
using System.Net;

using MailKit.Net.Pop3;
using MailKit;
using MimeKit;

namespace TestClient {
    class Program
    {
        public static void Main (string[] args)
        {
            using (var client = new Pop3Client ()) {
                client.Connect ("pop.gmail.com", 995, true);

                // Note: since we don't have an OAuth2 token, disable
                // the XOAUTH2 authentication mechanism.
                client.AuthenticationMechanisms.Remove ("XOAUTH2");

                client.Authenticate ("joey@gmail.com", "password");

                int count = client.GetMessageCount ();
                for (int i = 0; i < count; i++) {
                    var message = client.GetMessage (i);
                    Console.WriteLine ("Subject: {0}", message.Subject);
                }

                client.Disconnect (true);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)