SmtpClient的文檔現已改成:“廢棄(“SmtpClient及其相關類型設計很差,我們強烈建議使用https://github.com/jstedfast/MailKit和https://github.com/jstedfast/MimeKit替代。”)”。這是Microsoft有史以來第二次將一個.NET類正式標為被開源軟件庫替代。
MailKit和MimeKit的創建者是Jeffrey Stedfast,InfoQ曾在2014年采訪過他。在當時,它們已被認為是.NET上最全面的MIME和電子郵件庫。
Newtonsoft的JSON.NET是被Microsoft接受的首個重要開源庫。JSON.NET已在ASP.NET Web API中廣泛使用,并被正式推薦為Web API使用的序列化類,通常可替代JavaScriptSerializer類。但是不同于SmtpClient的是,沒有任何一個序列化類因此被標記為廢棄。
SmtpClient的主要問題在于連接生命周期管理混亂。由于連接SMTP服務器是一個非常耗時的操作,尤其是需要做認證時,因此每個SmtpClient對象都維護了一個內部連接池。
這是一個非常奇葩的設計。以典型的數據庫連接為例,當在SqlClient命名空間中調用Dispose方法時,底層的連接會返回到連接池中。當新建一個SqlClient時,需要檢查連接池中是否已具有連接串相同的活躍連接。
使用SmtpClient時,調用Dispose方法會關閉所有連接并清空對象的連接池。這意味著不能通過常規的“using”語句調用該方法。
你可能會想到,“那么我可以持續維護一個類似于HttpClient的共享實例”。但這也行不通。因為不同于在HttpClient中,Send和SendAsync方法并非是線程安全的。除非你引入了自定義的同步模式,否則不能以這種方式使用SmtpClient。事實上,SmtpClient的文檔中已給出了警告:
SmtpClient無法判定一個應用何時能完成,何時應被清除。
相比之下,MailKit的SMTP客戶端表示的是一個到單個服務器的簡單連接。它消除了由內部連接池所導致的復雜性。如果使用MailKit連接對象只需創建應用特定的連接池,這的確簡化了操作。
雖然活躍的MailKit軟件缺陷數非常少,但在對異步操作的真正支持上,它的確還存在著問題。要對已有軟件庫中添加異步操作,一般方法是拷貝全部方法并稍作修改以支持異步操作。在一些簡單的應用中,這并非難事。但是對于郵件客戶端這樣的復雜應用,這會導致一場噩夢。當前MailKit只是簡單地調用了同步代碼路徑和阻塞線程,模擬了對異步操作的支持。
解決異步問題的方案現在仍未確定,一個正在考慮的方案是使用AsyncRewriter工具。它是一個基于Roslyn的工具,已被PostgreSQL團隊用于將其同步代碼轉換為等價的異步代碼。
查看英文原文: MailKit Officially Replaces .NET’s SmtpClient