问题
i'm using MailKit to implement an IMAP email client. In the various examples i've seen that the code to fetch message headers is this one:
var messages = client.Inbox.Fetch (0, -1, MessageSummaryItems.Full | MessageSummaryItems.UniqueId).ToList();
If i have correctly understood, this fetches always ALL messages.
My idea is to save in a local db messages already fetched, and then, for subsequent fetches, getting only differences. Is there a way to accomplish this? Thanks
回答1:
Is there a way to accomplish this?
Yes, of course. The API allows you to request the information for any set of messages you want, whether you want to reference them by index or by UID.
The real question is "how?" and that all depends on two things:
- The IMAP extensions supported by your IMAP server
- The design of your email client and how you've chosen to populate your cache of message summary information (needed to populate your ListView or TreeView of messages in your UI).
If your IMAP server supports the QRESYNC extension, you'll want to read that specification so that you understand how best to use it as well as taking a look at the ImapFolder.Open (FolderAccess access, uint uidValidity, ulong highestModSeq, IList uids, CancellationToken cancellationToken) method.
If the IMAP server doesn't support QRESYNC, you might want to look into taking advantage of the CONDSTORE extension. You can take advantage of this extension by using any of the Fetch() or FetchAsync() methods that take a modseq
value.
In the end, your code will end up looking something like this (untested):
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);
And then you'd need to have at least the following event handlers:
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);
}
来源:https://stackoverflow.com/questions/54232790/mailkit-imap-fetch-only-new-not-downloaded-messages