MailKit IMAP извлекает только новые, не загруженные сообщения - PullRequest
0 голосов
/ 17 января 2019

Я использую MailKit для реализации почтового клиента IMAP. В различных примерах я видел, что код для извлечения заголовков сообщений:

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

Если я правильно понял, он всегда выбирает ВСЕ сообщения.

Моя идея состоит в том, чтобы сохранить в локальной базе данных уже выбранные сообщения, а затем, для последующих выборок, получать только различия. Есть ли способ сделать это? Спасибо

1 Ответ

0 голосов
/ 17 января 2019

Есть ли способ сделать это?

Да, конечно. API позволяет запрашивать информацию для любого набора сообщений, который вы хотите, независимо от того, хотите ли вы ссылаться на них по индексу или по UID.

Настоящий вопрос - как? и это все зависит от двух вещей:

  1. Расширения IMAP, поддерживаемые вашим сервером IMAP
  2. Дизайн вашего почтового клиента и то, как вы решили заполнить кэш сводной информацией о сообщениях (необходим для заполнения вашего ListView или TreeView сообщений в вашем пользовательском интерфейсе).

Если ваш IMAP-сервер поддерживает расширение QRESYNC , вам нужно прочитать эту спецификацию, чтобы понять, как лучше ее использовать, а также взглянуть на ImapFolder.Open ( Доступ к FolderAccess, uid uidValidity, ulong highModSeq, IList uids, CancellationToken cancellationToken) метод.

Если сервер IMAP не поддерживает QRESYNC, возможно, вы захотите воспользоваться преимуществом расширения CONDSTORE . Вы можете воспользоваться этим расширением, используя любой из методов Fetch () или FetchAsync (), которые принимают значение modseq.

В итоге ваш код будет выглядеть примерно так (не проверено):

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);
}
...