我正在使用MailKit实施IMAP电子邮件客户端。在各种示例中,我已经看到获取消息头的代码是这样的:
var messages = client.Inbox.Fetch (0, -1, MessageSummaryItems.Full | MessageSummaryItems.UniqueId).ToList();
如果我正确理解,它将始终获取所有消息。
我的想法是将已经获取的消息保存在本地db中,然后,对于后续的获取,仅获取差异。 有没有办法做到这一点? 谢谢
答案 0 :(得分:1)
有没有办法做到这一点?
是的,当然。该API允许您请求所需的任何消息集的信息,无论您是要通过索引还是通过UID引用它们。
真正的问题是“如何?”一切都取决于两件事:
如果您的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);
}