Mailkit 支持 Pop3、IMAP,STMP是目前.Net端最全的邮件开源项目了。
1、Pop3:跟其他的pop3操作类没有太大区别,跟OpenPop.NET等都差不多
2、IMAP:功能上比Pop3要强大太多,优势是功能强大、可以搜索邮箱的所有文件夹,Pop3只能搜索INBOX(收件箱),如果要做收信,还是IMAP首选。缺点是每一次操作都会与服务器同步,比如读取了邮件,服务器上也会变为已读,而Pop3不会。
如果做邮箱收信的话,还是必须同时支持 Pop3、IMAP。
大体使用方式:
1、在设计模式上实现一个抽象类GetEmail_base
2、然后再写一个IMAP、Pop3操作类并继承抽象类( GetMail_IMAP : GetEmail_base、GetMail_Pop : GetEmail_base)
3、最后在写一个GetEmail类对外使用,通过字段 private GetEmail_base GetEmail_Bll 将IMAP、Pop3操作合并统一操作邮件。
4、具体实现比较多,由于GetEmail类夹杂了很多我自有的判断,所以不方便上传。
今天要说的并不是Mailkit的基础操作,而是遇到过的一个大坑!!!!
在使用过程中,我曾遇到一个很蛋疼的问题,跑着跑着Mailkit 突然就卡住了,既不报错,也没有异常,就在那卡着,无论是Connect、Login又或者是其他任何操作,即便你设置了imapClient.Timeout、pop3Client.Timeout。
最开始十分疑惑,也没有找到原因,在尝试折腾了N次,并查看了源码之后发现,虽然我调用的是同步方法(Mailkit 支持异步),可是Mailkit 内部实际还是用的等待异步来执行的,而异步执行中有一个很重要的参数cancellationToken我没有填,因为这个参数支持默认值,一开始我以为既然有默认值,而且同步执行应该可以不需要设置这个参数,设置 Timeout就可以了,事实证明还是太年轻了。cancellationToken、Timeout分管的是两个不同的东西。
解决方法:在每个带有cancellationToken参数的方法中都带上自定义参数
var TokenSource = new CancellationTokenSource(30000);//30s超时
folder.Open(FolderAccess.ReadWrite, cancellationToken: TokenSource.Token);
var msg = folder.GetMessage(Index, cancellationToken: TokenSource.Token);
folder.Close(cancellationToken: TokenSource.Token);
imapClient.Identify(clientImplementation, cancellationToken: TokenSource.Token);
IMAP、Pop3都需要!!!设置好之后再也没有出现卡住不动的情况
ImapClient扩展类
public static class ImapClientEx
{
/// <summary>
/// task取消时间
/// </summary>
private static readonly int CancelTokenMillSecends = 30000;
/// <summary>
/// 模拟邮件客户端信息(是出自:https://www.cnblogs.com/zuimengaitianya/p/8579315.html)
/// </summary>
/// <param name="imapClient"></param>
public static void Identify(this ImapClient imapClient)
{
List<ImapImplementation> Implements = new List<ImapImplementation>()
{
new ImapImplementation() {Name = "foxmail",Version = "7.2.9.156", },
new ImapImplementation() {Name = "outlook",Version = "14.0.4760.1000", },
};
Func<ImapCapabilities, ImapCapabilities, bool> HasImapCapabilitiesId = (sourceFlag, targetFlag) => { return ((sourceFlag | targetFlag) == sourceFlag); };
if (HasImapCapabilitiesId(imapClient.Capabilities, ImapCapabilities.Id))
{
var clientImplementation = new ImapImplementation
{
Name = "foxmail",
Version = "7.2.9.156",
};
var TokenSource = new CancellationTokenSource(CancelTokenMillSecends);
var serverImplementation = imapClient.Identify(clientImplementation, cancellationToken: TokenSource.Token);
}
}
public static int GetMessageCount(this ImapClient imapClient, IMailFolder folder, bool closeFolder = false)
{
if (imapClient == null)
return 0;
var TokenSource = new CancellationTokenSource(CancelTokenMillSecends);
if (!folder.IsOpen)
folder.Open(MailKit.FolderAccess.ReadWrite, cancellationToken: TokenSource.Token);
var Count = folder.Count;
if (closeFolder)
folder.Close(cancellationToken: TokenSource.Token);
return Count;
}
public static int GetMessageCount(this ImapClient imapClient, IMailFolder folder, SearchQuery Query, bool closeFolder = false)
{
var Count = imapClient.GetManyMessageUids(folder, Query, closeFolder)?.Count;
return Count ?? 0;
}
public static List<UniqueId> GetManyMessageUids(this ImapClient imapClient, IMailFolder folder, SearchQuery Query, bool closeFolder = false)
{
if (imapClient == null)
return null;
//List<IMailFolder> mailFolderList = imapClient.GetFolders(imapClient.PersonalNamespaces[0]).ToList();//取所有文件夹
if (folder == null)
return null;
var TokenSource = new CancellationTokenSource(CancelTokenMillSecends);
if (!folder.IsOpen)
folder.Open(FolderAccess.ReadWrite, cancellationToken: TokenSource.Token);
var uids = folder.Search(Query, cancellationToken: TokenSource.Token);
if (closeFolder)
folder.Close(cancellationToken: TokenSource.Token);
return uids?.ToList();
}
public static MimeMessage GetMessage(this ImapClient imapClient, UniqueId Id, IMailFolder folder, bool closeFolder = false)
{
if (imapClient == null)
return null;
//List<IMailFolder> mailFolderList = imapClient.GetFolders(imapClient.PersonalNamespaces[0]).ToList();//取所有文件夹
if (folder == null)
return null;
var TokenSource = new CancellationTokenSource(CancelTokenMillSecends);
if (!folder.IsOpen)
folder.Open(MailKit.FolderAccess.ReadWrite, cancellationToken: TokenSource.Token);
var msg = folder.GetMessage(Id, cancellationToken: TokenSource.Token);
if (closeFolder)
folder.Close(cancellationToken: TokenSource.Token);
return msg;
}
public static MimeMessage GetMessage(this ImapClient imapClient, int Index, IMailFolder folder, bool closeFolder = false)
{
if (imapClient == null)
return null;
//List<IMailFolder> mailFolderList = imapClient.GetFolders(imapClient.PersonalNamespaces[0]).ToList();//取所有文件夹
if (folder == null)
return null;
var TokenSource = new CancellationTokenSource(CancelTokenMillSecends);
if (!folder.IsOpen)
folder.Open(FolderAccess.ReadWrite, cancellationToken: TokenSource.Token);
var msg = folder.GetMessage(Index, cancellationToken: TokenSource.Token);
if (closeFolder)
folder.Close(cancellationToken: TokenSource.Token);
return msg;
}
public static IList<IMessageSummary> FetchMessage(this ImapClient imapClient, List<UniqueId> Ids, IMailFolder folder, MessageSummaryItems Item, bool closeFolder = false)
{
if (imapClient == null)
return null;
//List<IMailFolder> mailFolderList = imapClient.GetFolders(imapClient.PersonalNamespaces[0]).ToList();//取所有文件夹
if (folder == null)
return null;
var TokenSource = new CancellationTokenSource(CancelTokenMillSecends);
if (!folder.IsOpen)
folder.Open(FolderAccess.ReadWrite, cancellationToken: TokenSource.Token);
var msg = folder.Fetch(Ids, Item, cancellationToken: TokenSource.Token);
if (closeFolder)
folder.Close(cancellationToken: TokenSource.Token);
return msg;
}
public static IList<IMessageSummary> FetchMessage(this ImapClient imapClient, List<int> indexes, IMailFolder folder, MessageSummaryItems Item, bool closeFolder = false)
{
if (imapClient == null)
return null;
//List<IMailFolder> mailFolderList = imapClient.GetFolders(imapClient.PersonalNamespaces[0]).ToList();//取所有文件夹
if (folder == null)
return null;
var TokenSource = new CancellationTokenSource(CancelTokenMillSecends);
if (!folder.IsOpen)
folder.Open(FolderAccess.ReadWrite, cancellationToken: TokenSource.Token);
var msg = folder.Fetch(indexes, Item, cancellationToken: TokenSource.Token);
if (closeFolder)
folder.Close(cancellationToken: TokenSource.Token);
return msg;
}
public static bool DeleteMessage(this ImapClient imapClient, UniqueId Id, IMailFolder folder, SearchQuery Query, bool closeFolder = false)
{
if (imapClient == null)
return false;
//List<IMailFolder> mailFolderList = imapClient.GetFolders(imapClient.PersonalNamespaces[0]).ToList();//取所有文件夹
if (folder == null)
return false;
var TokenSource = new CancellationTokenSource(CancelTokenMillSecends);
if (!folder.IsOpen)
folder.Open(FolderAccess.ReadWrite, cancellationToken: TokenSource.Token);
//设置状态
folder.SetFlags(Id, MessageFlags.Deleted, false, cancellationToken: TokenSource.Token);
//或者删除邮件
folder.RemoveFlags(Id, MessageFlags.Deleted, false);
//主要针对Exchange 让删除指令执行
folder.Expunge(cancellationToken: TokenSource.Token);
if (closeFolder)
folder.Close(cancellationToken: TokenSource.Token);
return true;
}
public static bool DeleteMessage(this ImapClient imapClient, int EmailIndex, IMailFolder folder, SearchQuery Query, bool closeFolder = false)
{
if (imapClient == null)
return false;
//List<IMailFolder> mailFolderList = imapClient.GetFolders(imapClient.PersonalNamespaces[0]).ToList();//取所有文件夹
if (folder == null)
return false;
var TokenSource = new CancellationTokenSource(CancelTokenMillSecends);
if (!folder.IsOpen)
folder.Open(FolderAccess.ReadWrite, cancellationToken: TokenSource.Token);
//设置状态
folder.SetFlags(EmailIndex, MessageFlags.Deleted, false, cancellationToken: TokenSource.Token);
//或者删除邮件
folder.RemoveFlags(EmailIndex, MessageFlags.Deleted, false, cancellationToken: TokenSource.Token);
//主要针对Exchange 让删除指令执行
folder.Expunge(cancellationToken: TokenSource.Token);
if (closeFolder)
folder.Close(cancellationToken: TokenSource.Token);
return true;
}
}