MailKit IMAP仅提取未下载的新消息

时间:2019-01-17 09:31:35

标签: c# imap mailkit mimekit

我正在使用MailKit实施IMAP电子邮件客户端。在各种示例中,我已经看到获取消息头的代码是这样的:

var messages = client.Inbox.Fetch (0, -1, MessageSummaryItems.Full | MessageSummaryItems.UniqueId).ToList();

如果我正确理解,它将始终获取所有消息。

我的想法是将已经获取的消息保存在本地db中,然后,对于后续的获取,仅获取差异。 有没有办法做到这一点? 谢谢

1 个答案:

答案 0 :(得分:1)

  

有没有办法做到这一点?

是的,当然。该API允许您请求所需的任何消息集的信息,无论您是要通过索引还是通过UID引用它们。

真正的问题是“如何?”一切都取决于两件事:

  1. 您的IMAP服务器支持的IMAP扩展
  2. 电子邮件客户端的设计以及如何选择填充消息摘要信息的缓存(需要在UI中填充消息的ListView或TreeView)。

如果您的IMAP服务器支持QRESYNC扩展名,那么您将需要阅读该规范,以便了解如何最好地使用它以及查看ImapFolder.Open (FolderAccess access, uint uidValidity, ulong highestModSeq, IList uids, CancellationToken cancellationToken)方法。

如果IMAP服务器不支持QRESYNC,则可能要考虑利用CONDSTORE扩展名。您可以使用任何采用modseq值的Fetch()或FetchAsync()方法来利用此扩展。

最后,您的代码最终看起来像这样(未经测试):

var uidValidity = cache.GetUidValidity ();
var known = cache.GetKnownUids ();
UniqueIdSet missing;

folder.MessageFlagsChanged += OnMessageFlagsChanged;

if (client.Capabilities.HasFlag (ImapCapabilities.QuickResync)) {
    var highestModSeq = cache.GetHighestKnownModSeq ();

    folder.MessagesVanished += OnMessagesVanished;

    // This version of the Open() method will emit MessagesVanished and MessageFlagsChanged
    // for all messages that have been expunged or have changed since the last session.
    folder.Open (FolderAccess.ReadWrite, uidValidity, highestModSeq, known);

    if (folder.UidValidity != uidValidity) {
        // our cache is no longer valid, we'll need to start over from scratch
        cache.Clear ();
        cache.SetUidValidity (folder.UidValidity);

        missing = folder.Search (SearchQuery.All);
    } else {
        // figure out which messages we are missing in our cache
        missing = new UniqueIdSet (SortOrder.Ascending);
        var all = folder.Search (SearchQuery.All);
        foreach (var uid in all) {
            if (!known.Contains (uid))
                missing.Add (uid);
        }
    }
} else {
    folder.MessageExpunged += OnMessageExpunged;
    folder.Open (ImapFolder.ReadWrite);

    if (folder.UidValidity != uidValidity) {
        // our cache is no longer valid, we'll need to start over from scratch
        cache.Clear ();
        cache.SetUidValidity (folder.UidValidity);

        missing = folder.Search (SearchQuery.All);
    } else {
        var all = folder.Search (SearchQuery.All);

        // purge messages from our cache that have been purged on the remote IMAP server
        foreach (var uid in known) {
            if (!all.Contains (uid))
                cache.Remove (uid);
        }

        // sync flag changes since our last session
        known = cache.GetKnownUids ();
        if (known.Count > 0) {
            IList<IMessageSummary> changed;
            if (client.Capabilities.HasFlag (ImapCapabilities.CondStore)) {
                var highestModSeq = cache.GetHighestKnownModSeq ();
                changed = folder.Fetch (known, highestModSeq, MessageSummaryItems.Flags | MessageSummaryItems.ModSeq | MessageSummaryItems.UniqueId);
            } else {
                changed = folder.Fetch (known, MessageSummaryItems.Flags | MessageSummaryItems.UniqueId);
            }

            foreach (var item in changed) {
                // update the cache for this message
                cache.Update (item);
            }
        }

        // figure out which messages we are missing in our cache
        missing = new UniqueIdSet (SortOrder.Ascending);
        foreach (var uid in all) {
            if (!known.Contains (uid))
                missing.Add (uid);
        }
    }
}

// fetch the summary information for the messages we are missing
var fields = MessageSummaryItems.Full | MessageSummaryItems.UniqueId;

if (client.Capabilities.HasFlag (ImapCapabilities.CondStore))
    fields |= MessageSummaryItems.ModSeq;

var newMessages = folder.Fetch (missing, fields);
foreach (var message in newMessages)
    cache.Add (message);

cache.SetHighestModSeq (folder.HighestModSeq);

然后,您至少需要具有以下事件处理程序:

void OnMessageFlagsChanged (object sender, MessageFlagsChangedEventArgs e)
{
    cache.Update (e.Index, e.Flags, e.ModSeq);
}

void OnMessageExpunged (object sender, MessageExpungedEventArgs e)
{
    cache.Remove (e.Index);
}

void OnMessagesVanished (object sender, MessagesVanishedEventArgs e)
{
    cache.RemoveRange (e.UniqueIds);
}