使用 .NET MVC 获取 gmail 电子邮件

Posted

技术标签:

【中文标题】使用 .NET MVC 获取 gmail 电子邮件【英文标题】:Fetching gmail emails using .NET MVC 【发布时间】:2016-06-25 14:22:07 【问题描述】:

我正在尝试创建一个小的网络应用程序来充当 Gmail 的网络邮件客户端...

我使用以下代码从我的收件箱中获取电子邮件:

   public ActionResult Index()
     
        using (var client = new ImapClient())
        
            using (var cancel = new CancellationTokenSource())
            
                ServicePointManager.ServerCertificateValidationCallback += (o, c, ch, er) => true;
                client.Connect("imap.gmail.com", 993, true, cancel.Token);

                // If you want to disable an authentication mechanism,
                // you can do so by removing the mechanism like this:
                client.AuthenticationMechanisms.Remove("XOAUTH");

                client.Authenticate("********@gmail.com", "****", cancel.Token);

                // The Inbox folder is always available...
                var inbox = client.Inbox;
                inbox.Open(FolderAccess.ReadOnly, cancel.Token);

                m = new List<string>();

                // download each message based on the message index
                for (int i = 0; i < inbox.length; i++)
                
                    var message = inbox.GetMessage(i, cancel.Token);
                    m.Insert(i, message.TextBody);
                



                client.Disconnect(true, cancel.Token);
            
        

        return View(m.ToList());
    

我不喜欢这种做法的原因是这部分代码:

  for (int i = 0; i < inbox.length; i++)
                    
                        var message = inbox.GetMessage(i, cancel.Token);
                        m.Insert(i, message.TextBody);
                    

提取所有邮件需要很长时间,大约每 5 秒提取 40 封邮件……所以如果有人有 2000 封邮件,加载所有邮件需要 20 分钟……

有没有更快的方法将所有电子邮件加载到我的 MVC 应用程序中? :/

附:我试过用有 10000 封电子邮件的电子邮件来做这件事,而且它需要很长时间才能获取所有电子邮件....

【问题讨论】:

这是什么 IMAP 库?它是否提供了一次获取多条消息的命令? 回应 Max 的问题,您使用的是什么 IMAP 库?您是否考虑过仅检索电子邮件标头?这会快得多,因为您没有检索身体和附件。如果用户想要打开特定的电子邮件,您可以这样做 这看起来像我的 IMAP 库 MailKit。 【参考方案1】:

如果您只需要邮件的正文,则可以使用以下方法减少 IMAP 流量:

var messages = inbox.Fetch (0, -1, MessageSummaryItems.UniqueId | MessageSummaryItems.BodyStructure);
int i = 0;

foreach (var message in messages) 
    var part = message.TextBody;

    if (part != null) 
        var body = (TextPart) inbox.GetBodyPart (message.UniqueId, part);
        m.Insert (i, body.Text);
     else 
        m.Insert (i, null);
    

    i++;

它的作用是向 IMAP 服务器发送批量 FETCH 请求,请求消息的“大纲”(也称为正文结构)及其唯一标识符。

紧随其后的循环会查看消息的结构,以找到包含消息正文的 MIME 部分,然后仅获取消息的特定子部分。

通常,您不会通过 IMAP 下载每条消息。 IMAP 的目的是将所有消息留在 IMAP 服务器上,并且只获取您需要的尽可能少的数据,以便向用户显示您想要显示的任何内容。

还应注意,您实际上不需要使用CancellationTokenSource,除非您确实计划能够取消操作。

例如,您的代码 sn-p 可以替换为:

public ActionResult Index()
 
    using (var client = new ImapClient())
    
        ServicePointManager.ServerCertificateValidationCallback += (o, c, ch, er) => true;
        client.Connect("imap.gmail.com", 993, true);

        // If you want to disable an authentication mechanism,
        // you can do so by removing the mechanism like this:
        client.AuthenticationMechanisms.Remove("XOAUTH");

        client.Authenticate("********@gmail.com", "****");

        // The Inbox folder is always available...
        var inbox = client.Inbox;
        inbox.Open(FolderAccess.ReadOnly);

        m = new List<string>();

        var messages = inbox.Fetch (0, -1, MessageSummaryItems.UniqueId | MessageSummaryItems.BodyStructure);
        int i = 0;

        foreach (var message in messages) 
            var part = message.TextBody;

            if (part != null) 
                var body = (TextPart) inbox.GetBodyPart (message.UniqueId, part);
                m.Insert (i, body.Text);
             else 
                m.Insert (i, null);
            

            i++;
        

        client.Disconnect(true);
    

    return View(m.ToList());

由于您正在为 GMail 编写自己的网络邮件前端,您可能会发现以下建议很有用:

当您查看 GMail 网络邮件用户界面或 Yahoo Mail! 的用户界面时,您可能已经注意到它们只向您显示最近的 50 条左右的邮件,您必须专门单击一个链接才能显示下一条一组 50 条消息等等,对吧?

这样做的原因是查询完整的消息列表并将它们全部下载(甚至只是所有消息的文本正文)效率低下。

他们所做的只是一次只要求 50 条消息。事实上,他们根本不要求消息,他们要求的摘要信息如下:

var all = inbox.Search (SearchQuery.All);
var uids = new UniqueIdSet ();

// grab the last 50 unique identifiers
int min = Math.Max (all.Count - 50, 0);
for (int i = all.Count - 1; i >= min; i--)
    uids.Add (all[i]);

// get the summary info needed to display a message-list UI
var messages = inbox.Fetch (uids, MessageSummaryItems.UniqueId | 
    MessageSummaryItems.All | MessageSummaryItems.BodyStructure);

foreach (var message in messages) 
    // the 'message' will contain a whole bunch of useful info
    // to use for displaying a message list such as subject, date,
    // the flags (read/unread/etc), the unique id, and the
    // body structure that you can use to minimize your query when
    // the user actually clicks on a message and wants to read it.

一旦用户点击消息阅读它,那么您可以使用message.Body 找出您实际上需要下载哪些正文部分以便将其显示给用户(即避免下载附件等)。

有关如何执行此操作的示例,请查看 MailKit GitHub 存储库中包含的 ImapClientDemo 示例:https://github.com/jstedfast/MailKit

【讨论】:

以上是关于使用 .NET MVC 获取 gmail 电子邮件的主要内容,如果未能解决你的问题,请参考以下文章

.Net通过Gmail发送邮件[重复]

使用 Gmail 的 .NET api 阅读大尺寸电子邮件

Gmail API .NET:如何向一位发件人请求邮件

从 gmail 获取消息 ID 非常慢

VB .Net 使用 Gmail 帐户发送电子邮件

通过 gmail 使用 System.Net.Mail 发送电子邮件