【问题标题】:Fetching gmail emails using .NET MVC使用 .NET MVC 获取 gmail 电子邮件
【发布时间】: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。

标签: asp.net-mvc email gmail imap


【解决方案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

【讨论】:

    猜你喜欢
    • 2023-03-14
    • 2016-08-10
    • 1970-01-01
    • 2018-11-03
    • 2021-05-07
    • 2019-01-22
    • 2021-03-04
    • 2014-08-19
    • 1970-01-01
    相关资源
    最近更新 更多