MicrosoftがSmtpClientをオープンソースライブラリに置き換えることを明らかにした。SmtpClientのドキュメントには、「廃止予定(SmtpClientとそのタイプのネットワークは設計が不十分であり、代わりに https://github.com/jstedfast/MailKit と https://github.com/jstedfast/MimeKit を使うことを強く推奨する)」と書かれている。
MailKitとMimeKitは、Jeffrey Stedfast氏によって作成されたライブラリだ。InfoQは2014年に、彼にインタビューした。その当時も、MailKitとMimeKitは、.NETのもっとも包括的なMIMEとメールのライブラリだとみなされていた。
Microsoftが最初に受け入れたオープンソースライブラリは、NewtonsoftのJSON.NETだった。これはASP.NET WebAPIで広く使われており、JavaScriptSerializerクラスの代替として公式に推奨され、一般的にDataContractJsonSerializerクラスよりも好まれている。ただし、SmtpClientとは違って、どちらのクラスも「廃止予定(obsolete)」にはなっていない。
SmtpClientの一番の問題は、接続ライフサイクルがわかりにくいことだ。SMTPサーバーへの接続には時間がかかる可能性がある。認証が有効な場合は特にそうだ。そのため、各SmtpClientオブジェクトは内部接続プールを持っている。
これはかなり奇妙な設計だ。よくあるデータベース接続の場合を考えてみよう。SqlClientでDisposeを呼び出すと、その接続はプールに戻される。そして、新しいSqlClientを作成するときには、同じ接続文字列をもつアクティブな接続がないか、プールをチェックするようになっている。
SmtpClientの場合、Disposeを呼び出すと、全ての接続がクローズされ、そのオブジェクトの接続プールは廃棄されてしまう。つまり、通常の‘using’ブロックパターンでは使えないのだ。
「HttpClientみたいな一つの共有インスタンスを持てばいい」と思うかもしれない。でも、だめだ。HttpClientと違って、Send/SendAsyncメソッドはスレッドセーフではない。そのため、独自の同期スキームを導入しない限り、そのような使い方はできない。実際、SmtpClientのドキュメントはこう警告している。
いつアプリケーションがSmtpClientオブジェクトを使うのをやめて、クリーンナップすべきかを判断するすべはありません。
これに対して、MailKitのSMTPクライアントは、一つのサーバーに対する単純な接続を表現している。内部接続プールによる複雑さはなく、アプリケーション固有のMailKit接続オブジェクト用プールを簡単に作ることができる。
アクティブなバグの数は驚くほど少ないが、MailKitには真の非同期サポートという問題がある。既存のライブラリに非同期サポートを追加する場合、メソッドをすべてコピーして、非同期サポートに必要な変更を少し加えるというやり方がよくとられる。こうしたコードの重複は、シンプルなアプリケーションの場合はそう厄介ではないが、メールクライアントのような複雑なアプリケーションの場合には、悪夢のようなメンテナンスに陥るおそれがある。そのため、彼らはとりあえず、同期コードパスを呼び出してスレッドをブロックすることで、非同期サポートをシミュレートしている。
この問題をどうするかは決まっていないが、検討すべき選択肢の一つは、AsyncRewriterツールだ。このRoslynベースのツールは、PostgreSQLチームが同期コードを同等の非同期コードに変換するのに使われている。
Rate this Article
- Editor Review
- Chief Editor Action