Smdn.Net.Pop3のドキュメントとサンプルです。 ここに記載されているものはversion 0.92時点のもので、記載不備などがあるかもしれません。
サンプルコードはこのページの最後にあります。 ご質問などありましたら掲示板へどうぞ。
このドキュメントでは、以下の表記を用いています。
上記以外は、RFC 1939および.NET Frameworkの用語に準じます。
本ライブラリはいくつかのアセンブリに分かれています。
| アセンブリ | 含まれる型 |
|---|---|
| Smdn.dll | 他のアセンブリで共通して使用される型、ユーティリティクラス、.NET Framework 4.x, 3.x互換の型など |
| Smdn.Core.Standards.dll | MIMEエンコード/デコード、URLエンコード/デコード等の標準に関するクラス群 |
| Smdn.Net.MessageAccessProtocols.dll | Smdn.Net.Pop3およびSmdn.Net.Imap4で共通して使用されるクラス群 |
| Smdn.Security.Authentication.Sasl.dll | Smdn.Security.Authentication.Sasl(SASLクライアントの実装) |
| Smdn.Net.Pop3.dll | POP3で使用される基本型等の定義 |
| Smdn.Net.Pop3.Client.dll | PopClient, PopSessionを含むPOP3クライアント実装 |
| Smdn.Net.Pop3.WebClients.dll | PopWebRequest/PopWebResponseを含むPOP3クライアント実装 |
本ライブラリを使用する場合は、上記アセンブリへの参照を追加してください(PopWebRequest/PopWebResponseを使用しない場合は、Smdn.Net.Pop3.WebClients.dllへの参照は不要です)。
クライアントの実装は次の3種類があります。
| 名前空間 | クラス | 概要 | 解説 |
|---|---|---|---|
| Smdn.Net.Pop3.Client (Smdn.Net.Pop3.Client.dll) |
PopClient PopMessageInfo |
POPの操作を抽象化したクラスです。 メッセージに対する操作をSystem.IO.FileInfoクラスに似たインターフェイスで行えるようにしてあります。 | PopClient |
| Smdn.Net.Pop3.WebClients (Smdn.Net.Pop3.WebClients.dll) |
PopWebRequest PopWebResponse |
POP URL(RFC 2384)を用いたクライアントの実装です。 System.Net.WebRequest/System.Net.WebResponseを継承しているので、メッセージのダウンロードにWebClientクラスのメソッドを使うこともできます。 System.Net.FtpWebRequest等と同様、WebRequest.Methodプロパティで送信するコマンドを制御できます。 |
PopWebRequest/PopWebResponse |
| Smdn.Net.Pop3.Client.Session (Smdn.Net.Pop3.Client.dll) |
PopSession | POPコマンドと1対1に対応するメソッドを持つクラスです。 POPの操作は抽象化していません。 仕様と1対1で対応するような実装にしてあります。 このクラスは上記2種類のクライアント実装で内部的に使用しています。 直接使用することもできますが、インターフェイスを変更することがあるので推奨はできません。 |
- |
ここでは各クライアント実装に共通する部分について解説します。 各クライアント実装の詳細については個別の解説を参照してください。
PopClientクラスおよびPopWebRequestクラスはPOP URLを使った接続に対応しています。 接続時の動作は、基本的にPOP URLの仕様に準じた動作となるようにしています※ただし、popsスキームを使用した場合にSSL/TLSでの接続を試みる動作は、仕様には無い、本ライブラリ独自の拡張です。
ここでは接続時と認証時の動作について解説します。
接続時の動作は、接続時のパラメータにより次のように変わります。
URLもしくはパラメータでポート番号を明示的に指定しない限り、デフォルトポートへの接続を試みます。 なお、ポート番号の指定ではSSL/TLSを使用するかどうかの動作は変わりません※ポート番号に995を指定してもURLのスキームが"pop"なら、接続時にSSL/TLSは使用しません。
例として接続先のURLと接続時の動作を表にまとめると以下のようになります。
| URL | 接続ポート | SSL/TLS |
|---|---|---|
| pops://user@pop.example.net/ | 995 | SSL/TLSを使用 |
| pops://user@pop.example.net:10110/ | 10110 | SSL/TLSを使用 |
| pop://user@pop.example.net/ | 110 | SSL/TLSを使用しない もしくは可能ならSSL/TLSへアップグレード |
| pop://user@pop.example.net:995/ | 995 | SSL/TLSを使用しない もしくは可能ならSSL/TLSへアップグレード |
これら接続時のパラメータは次の箇所で指定します。
接続にPOP URLを用いる場合、認証に用いるユーザ名と認証方式はURLから取得します。 パスワードはICredentialsByHostインターフェイス*1を参照し、接続しようとしているホスト名・ポート番号および指定された認証メカニズムをもとに適切なものを取得します。 POP URLではFTPやHTTPのURLとは異なり、URLに平文パスワードを含めることが許可されていないので、URLからはパスワードを取得しません(指定されていてもパスワードとしては解釈しません)。
認証方式にAPOPを使用する場合は、"APOP"ではなく"+APOP"を指定してください。 認証方式を指定しない場合、もしくは"*"が指定されている場合は次の順で認証を試行します。
URLもしくはパラメータでユーザ名・認証メカニズムの両方とも指定されていない場合は、ANONYMOUS認証を行います。 認証方式にANONYMOUSを指定して認証を行う場合、ユーザ名の部分をログイントークンとして送信します。 ユーザ名が指定されていない場合は"anonymous@"をログイントークンとして送信します。 ログイントークンに@などの記号を含める場合はURLエスケープする必要があります。
認証方式の大文字小文字の違いは無視します(POP URLの場合は';AUTH='の部分も大文字小文字を無視します)。
例として接続先のURLと認証時の動作を表にまとめると以下のようになります。
| URL | ユーザ名 | 使用する認証メカニズム |
|---|---|---|
| pop://user;AUTH=+APOP@pop.example.net/ | user | APOP |
| pop://user;AUTH=DIGEST-MD5@pop.example.net/ | user | DIGEST-MD5 |
| pop://;AUTH=DIGEST-MD5@pop.example.net/ | ICredentialsByHostインターフェイスより取得 | DIGEST-MD5 |
| pop://user;AUTH=*@pop.example.net/ | user | サーバ・クライアントが対応しているものを順に試行 |
| pop://user@pop.example.net/ | user | サーバ・クライアントが対応しているものを順に試行 |
| pop://;AUTH=ANONYMOUS@pop.example.net/ | 匿名ユーザ (ログイントークン: anonymous@) |
ANONYMOUS |
| pop://user@localhost;AUTH=ANONYMOUS@pop.example.net/ | 匿名ユーザ (ログイントークン: user@localhost) |
ANONYMOUS |
| pop://pop.example.net/ | 匿名ユーザ (ログイントークン: anonymous@) |
ANONYMOUSもしくはUSER/PASSコマンドを使用 |
試行する認証メカニズムを制御するには、UsingSaslMechanismsプロパティ*2の値を変更してください。 UsingSaslMechanismsプロパティにANONYMOUSが含まれていても匿名ログインは試行しません。 AllowInsecureLogin*3プロパティにfalseを指定した場合で、かつ現在の接続がSSL/TLSで保護されていない場合、平文およびAPOPによる認証は試行されません(デフォルトはfalseです)。
| サーバが対応している認証方式 | UsingSaslMechanismsの値 | 試行順序 (接続がSSL/TLSで保護されている、もしくはAllowInsecureLoginがtrueの場合) |
試行順序 (接続がSSL/TLSで保護されていない、かつAllowInsecureLoginがfalseの場合) |
|---|---|---|---|
| DIGEST-MD5 CRAM-MD5 APOP USER/PASS |
{"DIGEST-MD5", "CRAM-MD5"} | 1.DIGEST-MD5 2.CRAM-MD5 3.APOP 4.USER/PASS |
1.DIGEST-MD5 2.CRAM-MD5 |
| DIGEST-MD5 CRAM-MD5 PLAIN |
{"PLAIN", "DIGEST-MD5"} | 1.PLAIN 2.DIGEST-MD5 |
1.DIGEST-MD5 |
| PLAIN APOP USER/PASS |
null | 1.APOP 2.USER/PASS |
PopAuthenticationExceptionをスロー (試行できる認証方式なし) |
これら認証時のパラメータは次の箇所で指定します。
APOPを使用した認証については脆弱性が指摘されているため、本ライブラリではAPOPは平文による認証と同程度のものとして扱います。 参考:情報処理推進機構:情報セキュリティ:脆弱性関連情報取扱い:APOP方式におけるセキュリティ上の弱点(脆弱性)の注意喚起について
認証時に必要なユーザ名・パスワードはSystem.Net.ICredentialsByHostインターフェイスを通して取得します。 ICredentialsインターフェイスではなく、ICredentialsByHostインターフェイスを実装していて、GetCredentialメソッドが適切なSystem.Net.NetworkCredentialを返すクラスなら何でも設定できます。
PopWebRequest.CredentialsプロパティはWebRequestから継承しているためICredentialsインターフェイスを実装していることを要求しますが、設定されるインスタンスはICredentialsByHostも実装している必要があります。
現時点ではSecureStringに格納されたパスワードには対応していません。 NetworkCredential.SecurePasswordプロパティにパスワードが設定されていても無視します。
SSL/TLS接続時に使用する証明書はX509Certificate2Collectionで設定できます。 また、証明書の選択と検証にはRemoteCertificateValidationCallbackデリゲートとLocalCertificateSelectionCallbackデリゲートを指定できます。 デフォルトの状態では、SSL/TLS接続時にこれらのコールバックメソッドを呼び出して証明書の検証と選択を行い、SslStreamを作成します。
具体的な記述例はPopClientでの例およびPopWebRequestでの例を参照してください。
(このドキュメントは作成中です)
SslStream以外の実装を使いたい場合や、より高度な検証が必要な場合など、SSL/TLS接続時にデフォルトの動作を変更してカスタマイズする場合は、UpgradeConnectionStreamCallbackデリゲートを使用してコールバックメソッドを指定してください。
コールバックメソッドはPopClient.Connect()メソッドの引数、またはPopSessionManager.CreateSslStreamCallbackプロパティに指定してください。 実装例はPopConnection.CreateSslStreamメソッドを参照してください。
ライブラリからは主に以下の例外をスローします。 InnerExceptionプロパティに原因となった例外を設定した状態でスローする場合もあります。
| 例外クラス | スローされる状況 |
|---|---|
| PopInvalidOperationException および派生クラス (Smdn.Net.Pop3) |
プロトコル上不正な操作を行おうとした場合 認証に失敗した場合はPopAuthenticationException サーバに不正な要求を行おうとした場合はPopProtocolViolationException サーバがエラー応答を返した場合はPopErrorResponseException |
| PopConnectionException および派生クラス (Smdn.Net.Pop3.Protocol) |
接続に失敗した場合、ソケットエラーが発生した場合など SSL/TLSに起因するエラーの場合はPopUpgradeConnectionException |
| TimeoutException (System) | ソケット送受信中やコマンド処理中にタイムアウトした場合 |
| InvalidOperationException (System) | 現在のクライアントの状態に対して無効な操作を行おうとした場合 |
| ArgumentException および派生クラス (System) |
nullや値域外の値など、メソッド呼び出し時の引数が不正な場合 |
| WebException またはProtocolViolationException (System.Net) |
Smdn.Net.Pop3.WebClients名前空間で発生した例外は、これらの例外に変換した上でスローされます |
サーバ/クライアントのバグなどにより上記以外の例外がスローされる可能性もあります。 ログ出力を有効にしている場合、発生した例外はログに記録されます。
シンボルTRACEを有効にしてビルドした場合、トレースにログを出力します。 ログ出力に使用するTraceSourceの名前と、出力内容は次のとおりです。
| TraceSourceの名前 | 出力内容 |
|---|---|
| "Smdn.Net.Pop3.Client" | コマンドの送受信結果とセッション毎の動作ログ |
| "POP" | 送信するコマンドと受信したレスポンスの内容 |
ログ出力先などの設定を行う場合は、以下の例のようなアプリケーション構成ファイルを作成してください。
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.diagnostics> <sources> <source name="Smdn.Net.Pop3.Client" switchValue="Verbose"> <listeners> <add name="console" type="System.Diagnostics.ConsoleTraceListener"/> <remove name="Default"/> </listeners> </source> <source name="POP" switchValue="Verbose"> <listeners> <add name="log" type="System.Diagnostics.TextWriterTraceListener" initializeData="pop.log"/> <remove name="Default"/> </listeners> </source> </sources> <switches> <add name="switch" value="All"/> </switches> </system.diagnostics> </configuration>]]>
なお、SSL/TLSを使用しているかどうかに関わらず、ログにはパスワードを含む内容を平文で出力します。 ログの出力が不要な場合はTRACEを無効にしてリビルドするか、Trace.csなどを削除してください。
トレースにログを出力する際、出力内容はSmdn.Net.MessageAccessProtocols.Diagnosticsの各クラスのインスタンスとしてTraceSource.TraceData()メソッドに渡します。 トレース内容をカスタマイズする場合は、これらのクラスを使うことができます。
using System; using System.Diagnostics; using System.Text; using Smdn.Net; using Smdn.Net.MessageAccessProtocols.Diagnostics; using Smdn.Net.Pop3.Protocol.Client; public class CustomTraceListener : TraceListener { public CustomTraceListener(string name) : base(name) { } public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data) { if (data is ReceiveTraceData) { var received = data as ReceiveTraceData; var recv = Encoding.ASCII.GetString(received.Data.Array, received.Data.Offset, received.Data.Count); Write("受信内容:\t"); WriteLine(recv); } else if (data is SendTraceData) { var sent = data as SendTraceData; var snt = Encoding.ASCII.GetString(sent.Data.Array, sent.Data.Offset, sent.Data.Count); Write("送信内容:\t"); WriteLine(snt); } else if (data is MessageTraceData) { WriteLine((data as MessageTraceData).Message); } else if (data is ExceptionTraceData) { WriteLine((data as ExceptionTraceData).Exception); } else { base.TraceData(eventCache, source, eventType, id, data); } } public override void Write(string message) { // TODO } public override void WriteLine(string message) { // TODO } } public static class Test { [STAThread] public static void Main(string[] args) { // カスタマイズしたトレースリスナを追加 PopConnection.TraceSource.Listeners.Add(new CustomTraceListener("log")); : : } }
PopClientクラスおよびSmdn.Net.Pop3.Client名前空間のクラスの使い方。
基本的には、
の順でサーバ上のメッセージの取得と操作を行います。 以下でPopClientクラスの使い方について解説します。
接続・認証時の動作は、接続と認証で解説したとおりPOP URLに記述されるスキーム・ホスト名・ポート・認証方式・ユーザ名に基づいて決まります。 PopClientクラスではPOP URLは用いず、ホスト・ポート・認証方式・ユーザ名等を個々に指定することもできます。
以下はコード上での記述と接続・認証時の動作の例です。 実際にSSL/TLSを使用する場合は証明書の検証等が必要になります。
/* * ホスト"pop.example.net"のPOPSデフォルトポート(995)にSSL/TLSを用いて接続。 * ユーザ名に"user"、パスワードに"pass"を使用。 認証方式は対応しているものを順に試行。 */ var client1 = new PopClient(new Uri("pops://user@pop.example.net/")); client1.Connect("pass"); /* * ホスト"pop.example.net"のポート10110に接続、可能ならSSL/TLSにアップグレード。 * ユーザ名に"user"を使用、パスワードはNetworkCredentialから取得。 認証方式はAPOPを試行。 */ var client2 = new PopClient(new Uri("pop://user;AUTH=+APOP@pop.example.net:10110/")); client2.Profile.UseTlsIfAvailable = true; client2.Connect(new NetworkCredential("user", "pass")); /* * ホスト"pop.example.net"のポート10110にSSL/TLSを用いて接続。 * ユーザ名に"user"、パスワードに"pass"を使用。 認証方式はDIGEST-MD5を試行。 */ var client3 = new PopClient("pop.example.net", 10110, true, "user", "DIGEST-MD5"); client3.Connect("pass"); /* * ホスト"pop.example.net"のPOPデフォルトポート(110)に接続、SSL/TLSは使用しない。 * ユーザ名に"user"を使用、パスワードはNetworkCredentialから取得。 認証方式はDIGEST-MD5, CRAM-MD5, APOP, USER/PASSの順に試行。 */ var client4 = new PopClient("pop.example.net", -1, false, null, "*"); client4.Profile.UseTlsIfAvailable = false; client4.Profile.UsingSaslMechanisms = new[] {"DIGEST-MD5", "CRAM-MD5", "+APOP"}; client4.Connect(new NetworkCredential("user", "pass")); /* * ホスト"pop.example.net"のPOPデフォルトポート(110)に接続、可能ならSSL/TLSを使用する。 * ユーザ名に"user"を使用、パスワードはNetworkCredentialから取得。 * 認証方式はCRAM-MD5, PLAIN, APOP, USER/PASSの順に試行。 ただしSSL/TLSが使用できない場合、平文による認証を許可しない。 */ var client5 = new PopClient(new Uri("pop://user@pop.example.net/")); client5.Profile.UseTlsIfAvailable = true; client5.Profile.UsingSaslMechanisms = new[] {"CRAM-MD5", "PLAIN"}; client5.Profile.AllowInsecureLogin = false; client5.Connect(new NetworkCredential("user", "pass")); /* * GMailのアカウント"user"にPOPで接続。 パスワードは"pass"を使用。 */ var client6 = new PopClient(new Uri("pops://user@pop.gmail.com/")); client6.Connect("pass");
デフォルトでは、接続・認証時にPopConnectionクラス(Smdn.Net.Pop3.Protocol.Client名前空間)の以下のメンバを参照して証明書の選択と検証を行います。
| 型 | PopClientクラスが参照するメンバ |
|---|---|
| X509Certificate2Collection | PopConnection.ClientCertificates |
| RemoteCertificateValidationCallback | PopConnection.ServerCertificateValidationCallback |
| RemoteCertificateValidationCallback | PopConnection.ClientCertificateSelectionCallback |
以下は証明書の検証を行う簡単な例です。
using System; using System.Net; using System.Net.Security; using System.Security.Cryptography.X509Certificates; using Smdn.Net.Pop3; using Smdn.Net.Pop3.Client; using Smdn.Net.Pop3.Protocol.Client; public class ValidateServerCerts { public static void Main(string[] args) { // 証明書の検証を行うコールバックメソッドを指定 PopConnection.ServerCertificateValidationCallback += ValidateRemoteCertificate; using (var client = new PopClient(new Uri("pops://user@localhost/"))) { client.Connect("pass"); } } private static bool ValidateRemoteCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { #if DEBUG // デバッグ時のみSslPolicyErrors.RemoteCertificateNameMismatchを無視 if ((int)(sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) != 0) sslPolicyErrors &= ~SslPolicyErrors.RemoteCertificateNameMismatch; #endif if (sslPolicyErrors == SslPolicyErrors.None) { return true; } else { // エラーがあれば標準エラーに表示 Console.Error.WriteLine(sslPolicyErrors); return false; } } }
SSL/TLS接続時の動作をデフォルトからカスタマイズしたい場合は、PopClient.Connect()メソッドの引数に適切なコールバックメソッドを指定してください。
(このドキュメントは作成中です)
接続・切断およびメールボックスに対する操作はPopClientクラス、個々のメッセージに対する操作はPopMessageInfoクラスのインスタンスを用いて行います。 PopMessageInfoクラスのインスタンスは、PopClient.GetMessage()メソッドなどで取得します(直接インスタンスを作成することはできません)。
以下は接続・切断に関するメソッドとプロパティです。
| メソッド | 解説 | 対応するPOPコマンド |
|---|---|---|
| Connect(string) Connect(ICredentialsByHost) |
PopClient.Profileプロパティで指定された内容、および引数で指定されたパスワード(もしくはICredentialsByHost)を使って接続・認証を試みます。 接続・認証できた場合は、サーバの能力も取得します。 |
USER/PASS, STLS, APOP, AUTH, CAPA |
| BeginConnect(string) BeginConnect(string, AsyncCallback, object) BeginConnect(ICredentialsByHost) BeginConnect(ICredentialsByHost, AsyncCallback, object) |
Connect()メソッドと同じ処理を非同期的に実行します。 オプションでコールバックメソッドを指定できます。 | USER/PASS, STLS, APOP, AUTH, CAPA |
| EndConnect(IAsyncResult) | BeginConnecto()で開始した非同期接続を完了します。 BeginConnect()を呼び出した場合、EndConnect()で操作を完了する必要があります。 | - |
| Logout() | ログアウトします。 削除マークが付けられているメッセージは削除されます。 | QUIT |
| Disconnect() IDisposable.Dispose() |
ログアウトせずに切断します。 削除マークが付けられているメッセージがあっても削除されません。 | - |
| KeepAlive() | 自動ログアウトタイマの更新、セッションの接続性確認などに使います。 | NOOP |
| プロパティ | 解説 |
|---|---|
| Profile | 接続先のホスト・ポート・ユーザ名などを取得/設定します。 コンストラクタで指定した内容はこのプロパティに反映されます。 |
| Timeout | コマンド処理のタイムアウト時間をミリ秒単位で取得/設定します。 |
| SendTimeout | ソケット送信時のタイムアウト時間をミリ秒単位で取得/設定します。 |
| ReceiveTimeout | ソケット受信時のタイムアウト時間をミリ秒単位で取得/設定します。 |
| IsConnected | 接続中かどうかを表す値を取得します。 |
| ServerCapabilities | サーバがサポートする機能の一覧(CAPAコマンドの結果)を取得します。 |
以下はメールボックス操作に関するメソッドとプロパティです。
| メソッド | 解説 | 対応するPOPコマンド |
|---|---|---|
| CancelDelete() | すべてのメッセージに対して削除マークを元に戻し、削除要求をキャンセルします。 PopMessageInfo.MarkAsDeleted()で行った操作がキャンセルされます。 | RSET |
| プロパティ | 解説 |
|---|---|
| MessageCount | メールボックスに存在するメッセージの数を取得します。 |
| TotalSize | メールボックスに存在するメッセージの総サイズをバイト単位で取得します。 |
以下はメールボックスにあるメッセージを取得するメソッドの一覧です。
| メソッド | 解説 | 対応するPOPコマンド |
|---|---|---|
| GetMessage(long) GetMessage(long, bool) |
指定された番号のメッセージを取得します。 オプションでメッセージのIDも取得します。 最初の番号は1です。 | LIST, UIDL |
| GetMessage(string) | 指定されたIDを持つメッセージを取得します。 | LIST, UIDL |
| GetFirstMessage() GetFirstMessage(bool) |
メールボックスにある最初のメッセージを取得します。 オプションでメッセージのIDも取得します。 このメソッドを呼び出すことは、メッセージ番号に1を指定してGetMessage()を呼び出すこと同じです。 |
LIST, UIDL |
| GetLastMessage() GetLastMessage(bool) |
メールボックスにある最後のメッセージを取得します。 オプションでメッセージのIDも取得します。 このメソッドを呼び出すことは、メッセージ番号にPopClient.MessageCountを指定してGetMessage()を呼び出すこと同じです。 |
LIST, UIDL |
| GetMessages() GetMessages(bool) |
メールボックスにあるすべてのメッセージを取得します。 オプションでメッセージのIDも取得します。 | LIST, UIDL |
以下はメッセージ本文の取得に関するメソッド・プロパティの一覧です。
| メソッド | 解説 | 対応するPOPコマンド |
|---|---|---|
| OpenRead() およびオーバーロード |
メッセージ本文を読み込むためのStreamを取得します。 | RETRまたはTOP |
| OpenText() およびオーバーロード |
メッセージ本文を読み込むためのStreamReaderを取得します。 | RETRまたはTOP |
| ReadAllBytes() およびオーバーロード |
メッセージ本文をbyte[]で取得します。 | RETRまたはTOP |
| ReadAllLines() およびオーバーロード |
メッセージ本文をstring[]で取得します。 | RETRまたはTOP |
| ReadAllText() およびオーバーロード |
メッセージ本文をstringで取得します。 | RETRまたはTOP |
| ReadLines() およびオーバーロード |
メッセージ本文をIEnumerable<string>で取得します。 | RETRまたはTOP |
| ReadAs<TOutput>(Converter<Stream, TOutput>) およびオーバーロード |
メッセージ本文を読み込むためのStreamを取得し、指定されたConverter<Stream, TOutput>で変換された結果を取得します。 | RETRまたはTOP |
| ReadAs<TOutput>(Converter<StreamReader, TOutput>) およびオーバーロード |
メッセージ本文を読み込むためのStreamReaderを取得し、指定されたConverter<StreamReader, TOutput>で変換された結果を取得します。 | RETRまたはTOP |
| Save(string) およびオーバーロード |
メッセージ本文を指定されたファイルに保存します。 | RETRまたはTOP |
| WriteTo(Stream) およびオーバーロード |
メッセージ本文を指定されたStreamに書き込みます。 | RETRまたはTOP |
| WriteTo(BinaryWriter) およびオーバーロード |
メッセージ本文を指定されたBinaryWriterに書き込みます。 | RETRまたはTOP |
| プロパティ | 解説 |
|---|---|
| DeleteAfterRetrieve | PopMessageInfoクラスでメッセージ本文を取得する際、正常に取得できたらメッセージを削除マーク済みにするかどうかを取得/設定します。 このプロパティの値は、上記のメソッドの動作を変更します。 |
以下はメッセージの操作に関するメソッドとプロパティです。
| メソッド | 解説 | 対応するPOPコマンド |
|---|---|---|
| MarkAsDeleted() | メッセージを削除マーク済みにします。 すでに削除マーク済み(IsMarkedAsDeletedがtrue)の場合は何もしません。 | DELE |
| プロパティ | 解説 |
|---|---|
| IsMarkedAsDeleted | メッセージが削除マーク済みかどうかを表す値を取得します。 |
| MessageNumber | メッセージの番号を取得します。 |
| Length | メッセージのサイズをバイト単位で取得します。 |
| UniqueId | メッセージのID(UIDLコマンドの結果)を取得します。 |
PopClientクラスおよびPopMessageInfoクラスからは以下の例外をスローします。 ここに明記している以外の例外クラス・状況でスローされる場合があります。
| 例外クラス | 状況 | スローする可能性のあるメソッド |
|---|---|---|
| PopConnectionException | 接続に失敗した | PopClient.Connect() |
| PopUpgradeConnectionException | SSL/TLSへのアップグレードに失敗した 証明書を検証した結果無効と判断した |
PopClient.Connect() |
| PopAuthenticationException | 認証に失敗した 試行できる認証メカニズムが無い |
PopClient.Connect() |
| PopErrorResponseException | サーバがエラー応答を返した | PopClientおよびPopMessageInfoの各メソッド・プロパティ |
| PopProtocolViolationException | プロトコル上不正な操作を行おうとした | PopClientおよびPopMessageInfoの各メソッド・プロパティ |
| PopMessageDeletedException | 削除マーク済み(PopMessageInfo.IsMarkedAsDeletedがtrue)のメッセージに対して操作を行おうとした | PopClient.GetMessage() PopMessageInfoの各メソッド・プロパティ |
| PopMessageNotFoundException | 指定された番号もしくはIDを持つメッセージが存在しない | PopClient.GetMessage() PopClient.GetMessages() |
| InvalidOperationException | 切断された状態(PopClient.IsConnectedがfalse)で操作を行おうとした 非同期接続中に新たに接続を開始しようとした |
PopClientおよびPopMessageInfoの各メソッド・プロパティ |
| TimeoutException (System) | PopClient.Timeout, SendTimeout, ReceiveTimeoutプロパティで指定されている時間内に操作が完了しなかった | PopClientおよびPopMessageInfoの各メソッド・プロパティ |
それぞれの例外クラスの継承関係は次のとおりです。
現時点で非同期操作をサポートするメソッドは、PopClient.BeginConnect()/EndConnect()のみです。 PopMessageInfo.OpenRead()については、今後のバージョンで非同期操作をサポートする予定ですが、それ以外については予定はありません。
また現時点では、上記の非同期操作用のメソッドを除き、PopClientクラスおよびPopMessageInfoクラスはスレッドセーフではありません。 内部で使用している実装はスレッドセーフなので、処理内容によっては問題なく動作するかもしれませんが、保証はできません。 個々のインスタンスは同一スレッド内で使用してください。 今後のバージョンでスレッドセーフティを保証した実装に改善する予定です。
なお、アプリケーションドメインをまたがる使用については全く考慮していないため、動作および安全性の保証はできません。
ここではPopWebRequest/PopWebResponseクラスおよびSmdn.Net.Pop3.WebClients名前空間のクラスの詳細と使い方を紹介します。
基本的にはHttpWebRequest/HttpWebResponseやFtpWebRequest/FtpWebResponseを用いた操作と同様で、
の順でPOPコマンドを実行、レスポンスを取得します。 以下でPopWebRequest/PopWebResponseクラスに固有な部分について解説します。
WebRequestクラスがpopスキームおよびpopsスキームのURLを処理できるように、PopWebRequest/PopWebResponseクラスを使う前にPopWebRequestCreator.RegisterPrefixメソッドを呼び出しておく必要があります。
このメソッドはWebRequest.RegisterPrefixメソッドを呼び出し、popスキームおよびpopsスキームに対してPopWebRequestCreatorを関連付けます。
using System; using System.Net; using Smdn.Net.Pop3; using Smdn.Net.Pop3.WebClients; : : // popおよびpopsスキームの登録 PopWebRequestCreator.RegisterPrefix(); // PopWebRequestインスタンスの作成 var request = WebRequest.Create("pop://user@pop.example.net/"); : :
接続・認証時の動作は、接続と認証で解説したとおりリクエストURLに記述されるスキーム・ホスト名・ポート・認証方式・ユーザ名に基づいて決まります。
リクエストURLで記述されない接続・認証時の動作は、PopWebRequestクラスのプロパティで指定できます※PopWebRequestのプロパティも合わせて参照してください。
| プロパティ | 解説 |
|---|---|
| Credentials | 認証時に使用する資格情報(パスワード等)を指定します |
| UseTlsIfAvailable | 認証を開始する前に、可能ならSSL/TLSへアップグレードするかどうかを指定します |
| UsingSaslMechanisms | 認証時に試行する認証メカニズムを指定します |
| AllowInsecureLogin | 接続がSSL/TLSで保護されていない場合でも、平文またはAPOPによる認証を許可するかどうか指定します |
以下はコード上での記述と接続・認証時の動作の例です。 実際にSSL/TLSを使用する場合は証明書の検証等が必要になります。
// popおよびpopsスキームの登録 PopWebRequestCreator.RegisterPrefix(); /* * ホスト"pop.example.net"のPOPSデフォルトポート(995)にSSL/TLSを用いて接続。 * ユーザ名に"user"、パスワードに"pass"を使用。 認証方式は対応しているものを順に試行。 */ var request1 = WebRequest.Create(new Uri("pops://user@pop.example.net/")); request1.Credentials = new NetworkCredential("user", "pass"); /* * ホスト"pop.example.net"のポート10110に接続、可能ならSSL/TLSにアップグレード。 * ユーザ名に"user"、パスワードに"pass"を使用。 認証方式はAPOPを試行。 */ var request2 = WebRequest.Create(new Uri("pop://user;AUTH=+APOP@pop.example.net:10110/")) as PopWebRequest; request2.UseTlsIfAvailable = true; request2.Credentials = new NetworkCredential("user", "pass"); /* * ホスト"pop.example.net"のポート10110にSSL/TLSを用いて接続。 * ユーザ名に"user"、パスワードに"pass"を使用。 認証方式はDIGEST-MD5を試行。 */ var request3 = WebRequest.Create(new Uri("pops://user;AUTH=DIGEST-MD5@pop.example.net:10110/")) as PopWebRequest; request3.Credentials = new NetworkCredential("user", "pass"); /* * ホスト"pop.example.net"のPOPデフォルトポート(110)に接続、SSL/TLSは使用しない。 * ユーザ名に"user"、パスワードに"pass"を使用。 認証方式はDIGEST-MD5, CRAM-MD5, APOP, USER/PASSの順に試行。 */ var request4 = WebRequest.Create(new Uri("pop://;AUTH=*@pop.example.net/")) as PopWebRequest; request4.UseTlsIfAvailable = false; request4.UsingSaslMechanisms = new[] {"DIGEST-MD5", "CRAM-MD5", "+APOP"}; request4.Credentials = new NetworkCredential("user", "pass"); /* * ホスト"pop.example.net"のPOPデフォルトポート(110)に接続、可能ならSSL/TLSを使用する。 * ユーザ名に"user"、パスワードに"pass"を使用。 * 認証方式はCRAM-MD5, PLAIN, APOP, USER/PASSの順に試行。 ただしSSL/TLSが使用できない場合、平文による認証を許可しない。 */ var request5 = WebRequest.Create(new Uri("pop://user@pop.example.net/")) as PopWebRequest; request5.UseTlsIfAvailable = true; request5.UsingSaslMechanisms = new[] {"CRAM-MD5", "PLAIN"}; request5.AllowInsecureLogin = false; request5.Credentials = new NetworkCredential("user", "pass"); /* * GMailのアカウント"user"にPOPで接続。 パスワードは"pass"を使用。 */ var request6 = WebRequest.Create(new Uri("pops://user@pop.gmail.com/")); request6.Credentials = new NetworkCredential("user", "pass");
デフォルトでは、接続・認証時にPopSessionManagerクラスの以下のメンバを参照して証明書の選択と検証を行います。
| 型 | PopWebRequestクラスが参照するメンバ |
|---|---|
| X509Certificate2Collection | PopSessionManager.ClientCertificates |
| RemoteCertificateValidationCallback | PopSessionManager.ServerCertificateValidationCallback |
| RemoteCertificateValidationCallback | PopSessionManager.ClientCertificateSelectionCallback |
以下は証明書の検証を行う簡単な例です。
using System; using System.Net; using System.Net.Security; using System.Security.Cryptography.X509Certificates; using Smdn.Net.Pop3; using Smdn.Net.Pop3.WebClients; public class ValidateServerCerts { public static void Main(string[] args) { PopWebRequestCreator.RegisterPrefix(); // 証明書の検証を行うコールバックメソッドを指定 PopSessionManager.ServerCertificateValidationCallback += ValidateRemoteCertificate; using (var client = new WebClient()) { client.Credentials = new NetworkCredential("user", "pass"); client.DownloadFile("pops://user@localhost/;MSG=1", "sample.eml"); } } private static bool ValidateRemoteCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { #if DEBUG // デバッグ時のみSslPolicyErrors.RemoteCertificateNameMismatchを無視 if ((int)(sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch) != 0) sslPolicyErrors &= ~SslPolicyErrors.RemoteCertificateNameMismatch; #endif if (sslPolicyErrors == SslPolicyErrors.None) { return true; } else { // エラーがあれば標準エラーに表示 Console.Error.WriteLine(sslPolicyErrors); return false; } } }
SSL/TLS接続時の動作をデフォルトからカスタマイズしたい場合は、PopSessionManager.CreateSslStreamCallbackに適切なコールバックメソッドを指定してください。
POP URL(RFC 2384)ではPOPサーバ(メールボックス)を表す形式しか規定されていませんが、本ライブラリでは独自の拡張としてメッセージ番号を指定してリクエストできるようにしてあります。 リクエストURLにメッセージ番号(;MSG=x)が含まれているかどうかでリクエストの対象が変わります。
| リクエストURLの形式 | リクエストの対象 |
|---|---|
| pop://pop.example.net/ | URLで指定されたメールボックス |
| pop://pop.example.net/;MSG=1 | URLで指定されたメールボックスにあるメッセージのうち、メッセージ番号に該当する特定のメッセージ |
WebRequest.Createメソッドが返すWebRequestインスタンスのMethodプロパティにデフォルトで設定される値は、リクエストURLの形式によって決まります。
PopWebRequest.GetResponseの動作は、リクエストURLで表されるリクエストの対象と、WebRequest.Methodプロパティに設定する値によって変わります。 以下でリクエストURLの形式とMethodプロパティに指定可能な値、リクエストとレスポンスについて解説します。 PopWebRequestクラスのプロパティのうち、リクエストに影響するその他のプロパティについてはPopWebRequestのプロパティで説明します。
リクエストURLがメールボックスを表す場合(pop://pop.example.net/の形式)のリクエストとレスポンスの動作は次のとおりです。
| Methodプロパティ | リクエスト | 解説 | レスポンス |
|---|---|---|---|
| Methodプロパティ | リクエスト | 解説 | レスポンス |
| PopWebRequestMethods.List, "LIST" (デフォルト) |
LISTコマンドを送信してメールボックスにあるメッセージの一覧を取得します。 | - | 取得したメッセージの一覧は、PopWebResponse.ScanListsプロパティに設定されます。 |
| PopWebRequestMethods.Rset, "RSET" | RSETコマンドを送信してDELEコマンドの操作をキャンセルします。 | - | |
| PopWebRequestMethods.Stat, "STAT" | STATコマンドを送信してメールボックスにあるメッセージの数と総サイズを取得します。 | - | 取得したメッセージ数と総サイズは、PopWebResponse.DropListプロパティに設定されます。 |
| PopWebRequestMethods.Uidl, "UIDL" | UIDLコマンドを送信してメールボックスにあるメッセージのIDの一覧を取得します。 | - | 取得したIDの一覧は、PopWebResponse.UniqueIdListsプロパティに設定されます。 |
リクエストURLが特定のメッセージを表す場合(pop://pop.example.net/;MSG=1の形式)のリクエストとレスポンスの動作は次のとおりです。
| Methodプロパティ | リクエスト | 解説 | レスポンス |
|---|---|---|---|
| Methodプロパティ | リクエスト | 解説 | レスポンス |
| PopWebRequestMethods.Retr, "RETR" (デフォルト) |
RETRコマンドを送信してメッセージの本文を取得します。 | - | メッセージ本文はWebResponse.GetResponseStreamメソッドが返すStreamから読み込めます。 取得したメッセージのサイズはWebResponse.ContentLengthプロパティに設定されます。 |
| PopWebRequestMethods.Dele, "DELE" | DELEコマンドを送信してメッセージを削除します。 | - | - |
| PopWebRequestMethods.List, "LIST" | LISTコマンドを送信してメッセージの番号とサイズを取得します。 | - | 取得したメッセージ番号とサイズは、PopWebResponse.ScanListsプロパティに設定されます。 |
| PopWebRequestMethods.Top, "TOP" | TOPコマンドを送信してメッセージをヘッダ部分を取得します。 | 現時点ではTOPで取得するボディ部分の行数は指定できません(常に0を指定します)。 | メッセージのヘッダ部分はWebResponse.GetResponseStreamメソッドが返すStreamから読み込めます。 取得したヘッダ部分のサイズはWebResponse.ContentLengthプロパティに設定されます。 |
| PopWebRequestMethods.Uidl, "UIDL" | UIDLコマンドを送信してメッセージの番号とIDを取得します。 | - | 取得したメッセージ番号とIDは、PopWebResponse.UniqueIdListsプロパティに設定されます。 |
リクエストURLの形式によらず使用可能なコマンドのリクエストとレスポンスの動作は次のとおりです。
| Methodプロパティに指定可能な値 | リクエスト | 解説 | レスポンス |
|---|---|---|---|
| Methodプロパティに指定可能な値 | リクエスト | 解説 | レスポンス |
| PopWebRequestMethods.NoOp, "NOOP" | NOOPコマンドを送信します。 | このコマンドは何もしません。 自動ログアウトタイマの更新、セッションの接続性確認などに使います。 | - |
PopWebRequestクラスにはMethodプロパティ以外にもコマンド送信時の動作を制御するためのプロパティを用意してあります。 プロパティの値によってリクエスト内容と動作が変わります。
| プロパティ | デフォルト | 対象となるコマンド | 解説 |
|---|---|---|---|
| KeepAlive | true | 全て | リクエストが終了した後もセッションを維持するかどうかを指定します。 trueの場合はリクエストが終了してもセッションは維持し、falseの場合はリクエストの度にセッションを開きリクエスト終了と同時にセッションを閉じます。 |
| UseTlsIfAvailable | true | 全て(認証時) | サーバがサポートしている場合、認証を行う前にSSL/TLSを使用した接続にアップグレードします。 |
| UsingSaslMechanisms | {"DIGEST-MD5", "CRAM-MD5", "NTLM"} | 全て(認証時) | 認証メカニズムが指定されていない場合に、試行する認証メカニズムとその順番を配列で指定します。 サーバ・クライアントの両方がサポートするメカニズム以外が指定されている場合は無視します。 |
| AllowInsecureLogin | false | 全て(認証時) | 接続がSSL/TLSで保護されていない場合でも、平文またはAPOPによる認証を許可するかどうか指定します。 |
| DeleteAfterRetrieve | false | RETR | RETRコマンドでのメッセージの受信が成功した場合、同じメッセージに対して自動的にDELEコマンドを発行します。 |
| ExpectedErrorResponseCodes | null | 全て | サーバから返されることが予期されるエラーレスポンスコードの配列を指定します。 サーバからこれらのレスポンスコードが返された場合は、エラーレスポンスでもWebExceptionがスローされません。 |
WebRequestクラスから継承されるプロパティのうち、以下のプロパティは使用することができます。
| プロパティ | デフォルト | 対象となるコマンド | 解説 |
|---|---|---|---|
| Timeout | -1 | 全て | リクエストを開始してからレスポンスを取得するまでのタイムアウト時間を指定します。 |
| ReadWriteTimeout | 300000 | 全て | ソケット送受信のタイムアウト時間を指定します。 |
PopWebRequestDefaultsクラスのプロパティの値を変更することにより、PopWebRequestクラスのプロパティに設定されるデフォルト値を一括して指定することができます。 全てのリクエストでデフォルトの値を変更したい場合は、PopWebRequestDefaultsクラスのプロパティの値を変更してください。
PopWebRequestDefaultsクラスにはPopWebRequestプロパティと同名のプロパティを用意してあります。
アプリケーション構成ファイルを記述することにより、pop, popsスキームの登録と、PopWebRequestDefaultsクラスのデフォルト値を変更することができます。 コード上での変更をしたくない場合、する必要がない場合などは、アプリケーション構成ファイルに設定を記述することができます。 以下はアプリケーション構成ファイルの記述例です。
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <!-- smdn.net.pop3.client要素を処理するためのセクションハンドラクラスの設定 --> <sectionGroup name="smdn.net.pop3.client"> <section name="webRequestDefaults" type="System.Configuration.DictionarySectionHandler, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> </sectionGroup> </configSections> <system.net> <!-- pop, popsスキームの登録 --> <webRequestModules> <add prefix="pop" type="Smdn.Net.Pop3.WebClients.PopWebRequestCreator, Smdn.Net.Pop3.WebClients" /> <add prefix="pops" type="Smdn.Net.Pop3.WebClients.PopWebRequestCreator, Smdn.Net.Pop3.WebClients" /> </webRequestModules> </system.net> <smdn.net.pop3.client> <!-- PopWebRequestDefaultsクラスのデフォルト値の変更 --> <webRequestDefaults> <add key="timeout" value="-1"/> <add key="readWriteTimeout" value="-1"/> <add key="useTlsIfAvailable" value="true"/> <add key="deleteAfterRetrieve" value="false"/> <add key="keepAlive" value="true"/> <add key="usingSaslMechanisms" value="DIGEST-MD5, CRAM-MD5, NTLM"/> <add key="allowInsecureLogin" value="false"/> <add key="expectedErrorResponseCodes" value="SYS/TEMP"/> </webRequestDefaults> </smdn.net.pop3.client> </configuration>]]>
記述内容についてはネットワーク設定スキーマおよび構成セクション スキーマも合わせて参照してください。
PopWebRequestからはSystem.Net.WebExceptionまたはSystem.Net.ProtocolViolationExceptionをスローします。 WebExceptionをスローする場合は、エラーの状況によりWebException.StatusプロパティとInnerExceptionプロパティに値が設定されます。 また、サーバがエラー応答を返した場合は、Responseプロパティも設定されます。
InnerExceptionプロパティに設定される例外クラスについては、例外を参照してください。
WebRequestから継承されるBeginGetResponse()/EndGetResponse()メソッドは実装済みのため、これらのメソッドを使って非同期操作を行えます。 ただし、.NET Framework上では、WebClient.OpenReadAsync()、WebClient.Download*Async()などのメソッドを使用した非同期操作は正しく動作しないようなので、現時点では使用できません。
各クライアント実装を用いたサンプルコードを例示します。 証明書の検証を省略している箇所がありますが、実際に使用するコードでは必ず適切な検証を行うように書き換えてください。
using System; using Smdn.Net.Pop3; using Smdn.Net.Pop3.Client; class SaveToFile { public static void Main(string[] args) { using (var client = new PopClient(new Uri("pop://user;AUTH=DIGEST-MD5@localhost/"))) { client.Connect("pass"); // メールボックスにある1件目のメッセージをダウンロード var message = client.GetFirstMessage(); // ファイルsample.emlに保存 message.Save("sample.eml"); } } }
同じ処理をPopWebRequestで記述した例
using System; using System.Net; using System.Text; using Smdn.Net.Pop3; using Smdn.Net.Pop3.Client; using Smdn.Net.Pop3.Protocol.Client; class GpopRetrieveRecent { public static void Main(string[] args) { PopConnection.ServerCertificateValidationCallback += delegate { // 証明書の検証は省略 (エラーを無視してすべて受け入れる) return true; }; using (var client = new PopClient(new Uri("pops://user@pop.gmail.com/"))) { client.Connect("pass"); if (client.MessageCount == 0) { // メールボックスにメッセージがない Console.WriteLine("no messages"); return; } // メールボックスにある最後のメッセージを取得 var message = client.GetLastMessage(); // メッセージ本文をダウンロードし、iso-2022-jpでデコードして表示 Console.WriteLine(message.ReadAllText(Encoding.GetEncoding("iso-2022-jp"))); } } }
同じ処理をPopWebRequestで記述した例
using System; using Smdn.Net.Pop3; using Smdn.Net.Pop3.Client; using Smdn.Net.Pop3.Protocol.Client; class SaveAndDelete { public static void Main(string[] args) { PopConnection.ServerCertificateValidationCallback += delegate { // 証明書の検証は省略 (エラーを無視してすべて受け入れる) return true; }; using (var client = new PopClient(new Uri("pops://user;auth=ntlm@localhost/"))) { client.Connect("pass"); // メッセージ本文を取得したら削除する client.DeleteAfterRetrieve = true; // メールボックスにあるすべてのメッセージとIDを取得 foreach (var message in client.GetMessages(true)) { // IDをファイル名として保存 (IDがファイル名として妥当かどうかのチェックは省略) message.Save(message.UniqueId + ".eml"); } // ログアウトしてメッセージを削除 client.Logout(); } } }
上記のコードは、次のコードと等価です。
: client.DeleteAfterRetrieve = false; // メールボックスにあるすべてのメッセージとIDを取得 foreach (var message in client.GetMessages(true)) { // IDをファイル名として保存 (IDがファイル名として妥当かどうかのチェックは省略) message.Save(message.UniqueId + ".eml"); // 保存できたら削除マークを付ける message.MarkAsDeleted(); } : :
using System; using System.Collections.Generic; using System.Threading; using Smdn.Net.Pop3; using Smdn.Net.Pop3.Client; class CheckRecent { public static void Main(string[] args) { // 既知のメッセージID var ids = new List<string>(); using (var client = new PopClient(new Uri("pop://user;auth=ntlm@localhost/"))) { client.Profile.UseTlsIfAvailable = false; for (;;) { client.Connect("pass"); if (!client.ServerCapabilities.Has(PopCapability.Uidl)) // サーバがUIDLをサポートしていない throw new ApplicationException("UIDL incapable"); // メールボックスにあるすべてのメッセージを取得 foreach (var message in client.GetMessages(true)) { // 既知のメッセージIDかどうかチェック if (ids.Contains(message.UniqueId)) { // 既知の場合は何もしない } else { // 新着の場合は、メッセージ本文のヘッダのみを取得 foreach (var line in message.ReadLines(0)) { // ヘッダのうち"Subject:"で始まる行のみを表示 if (line.StartsWith("Subject:", StringComparison.OrdinalIgnoreCase)) Console.WriteLine("{0}: {1}", message.UniqueId, line); } // 既知のメッセージIDとして追加 ids.Add(message.UniqueId); } } // いったん切断 client.Disconnect(); // 5分後に再接続する Thread.Sleep(TimeSpan.FromMinutes(5.0)); } } } }(); using (var client = new PopClient(new Uri("pop://user;auth=ntlm@localhost/"))) { client.Profile.UseTlsIfAvailable = false; for (;;) { client.Connect("pass"); if (!client.ServerCapabilities.Has(PopCapability.Uidl)) // サーバがUIDLをサポートしていない throw new ApplicationException("UIDL incapable"); // メールボックスにあるすべてのメッセージを取得 foreach (var message in client.GetMessages(true)) { // 既知のメッセージIDかどうかチェック if (ids.Contains(message.UniqueId)) { // 既知の場合は何もしない } else { // 新着の場合は、メッセージ本文のヘッダのみを取得 foreach (var line in message.ReadLines(0)) { // ヘッダのうち"Subject:"で始まる行のみを表示 if (line.StartsWith("Subject:", StringComparison.OrdinalIgnoreCase)) Console.WriteLine("{0}: {1}", message.UniqueId, line); } // 既知のメッセージIDとして追加 ids.Add(message.UniqueId); } } // いったん切断 client.Disconnect(); // 5分後に再接続する Thread.Sleep(TimeSpan.FromMinutes(5.0)); } } } }]]>
この例において、初回の接続の時点ではidsは空なので、メールボックスにあるメッセージはすべて新着として扱われます。
メッセージをダウンロードした後、Smdn.Formats.Mimeを使ってパース・デコードする例。
using System; using Smdn.Net.Pop3; using Smdn.Net.Pop3.Client; using Smdn.Formats.Mime; class DecodeMime { public static void Main(string[] args) { using (var client = new PopClient(new Uri("pop://user;auth=ntlm@localhost/"))) { client.Profile.UseTlsIfAvailable = false; client.Connect("pass"); // すべてのメッセージを取得 foreach (var message in client.GetMessages()) { // メッセージの本文を取得し、MimeMessage.Loadメソッドでパース・デコードした結果を得る var decodedMessage = message.ReadAs<MimeMessage>(MimeMessage.Load); // デコードしたメッセージの件名を表示 Console.WriteLine("====[{0}: {1}]{2}", message.MessageNumber, decodedMessage.Headers["Subject"].Value, new string('=', 32)); // デコードした本文を表示 if (parsedMessage.MimeType.TypeEqualsIgnoreCase("text")) Console.WriteLine(decodedMessage.ReadContentAsText()); else Console.WriteLine("非テキストメッセージです"); } } } }(MimeMessage.Load); // デコードしたメッセージの件名を表示 Console.WriteLine("====[{0}: {1}]{2}", message.MessageNumber, decodedMessage.Headers["Subject"].Value, new string('=', 32)); // デコードした本文を表示 if (parsedMessage.MimeType.TypeEqualsIgnoreCase("text")) Console.WriteLine(decodedMessage.ReadContentAsText()); else Console.WriteLine("非テキストメッセージです"); } } } }]]>
using System; using System.Net; using Smdn.Net.Pop3.WebClients; class SaveToFile { public static void Main(string[] args) { PopWebRequestCreator.RegisterPrefix(); using (var client = new WebClient()) { client.Credentials = new NetworkCredential("user", "pass"); // メールボックスにある1件目のメッセージをダウンロードしてファイルsample.emlに保存 client.DownloadFile("pop://user;AUTH=DIGEST-MD5@localhost/;MSG=1", "sample.eml"); } } }
同じ処理をPopClientで記述した例
using System; using System.IO; using System.Text; using System.Net; using Smdn.Net.Pop3; using Smdn.Net.Pop3.WebClients; class GpopRetrieveRecent { public static void Main(string[] args) { PopWebRequestCreator.RegisterPrefix(); PopSessionManager.ServerCertificateValidationCallback += delegate { // 証明書の検証は省略 (エラーを無視してすべて受け入れる) return true; }; var baseUrl = new Uri("pops://user@pop.gmail.com/"); var credential = new NetworkCredential("user", "pass"); // STATコマンドでメールボックスにあるメッセージの数を取得 var request = WebRequest.Create(baseUrl) as PopWebRequest; request.Credentials = credential; request.Method = "STAT"; request.KeepAlive = true; // リクエストが完了しても接続したままにする long recentMessageNumber; using (var response = request.GetResponse() as PopWebResponse) { recentMessageNumber = response.DropList.MessageCount; } if (recentMessageNumber == 0) { // メールボックスにメッセージがない Console.WriteLine("no messages"); return; } // 取得するメッセージ番号を含む相対URLを作成 var recentMessageUrl = string.Format("./;MSG={0}", recentMessageNumber); // RETRコマンドでメッセージの本文を取得 request = WebRequest.Create(new Uri(baseUrl, recentMessageUrl)) as PopWebRequest; request.Credentials = credential; request.Method = "RETR"; request.KeepAlive = false; // リクエストが完了したら切断する using (var response = request.GetResponse()) { using (var stream = response.GetResponseStream()) { // メッセージ本文をiso-2022-jpでデコードして表示 var reader = new StreamReader(stream, Encoding.GetEncoding("iso-2022-jp")); Console.WriteLine(reader.ReadToEnd()); } } } }
同じ処理をPopClientで記述した例
このクラスを直接使用することはできますが推奨はしません。 また、ドキュメントを用意する予定はありません。 内部実装の参照や改変などの参考程度に掲載します。
Gmailに接続し、最新のメッセージを取得し、表示したあと削除するサンプル。
using System; using System.IO; using System.Text; using System.Net; using Smdn.Net.Pop3; using Smdn.Net.Pop3.Client.Session; using Smdn.Net.Pop3.Protocol.Client; class Sample { public static void Main(string[] args) { PopConnection.ServerCertificateValidationCallback += delegate { // 証明書の検証は省略 (エラーを無視してすべて受け入れる) return true; }; using (var session = new PopSession("pop.gmail.com", 995, PopConnection.CreateSslStream)) { var cred = new NetworkCredential("user", "pass"); // 利用可能ならAPOP、そうでなければUSER/PASSでログイン var authenticationResult = session.ApopAvailable ? session.Apop(cred) : session.Login(cred); if (authenticationResult.Failed) { Console.Error.WriteLine("authentication failed"); return; } // STATコマンドを発行 PopDropListing dropList; if (session.Stat(out dropList).Failed) { Console.Error.WriteLine("STAT failed"); return; } if (dropList.MessageCount == 0L) { // メールボックスにメッセージがない Console.Error.WriteLine("no message exists"); return; } // RETRコマンドでメッセージ本文を取得・表示 PopMessage message; if (session.Retr(dropList.MessageCount, out message).Failed) { Console.Error.WriteLine("RETR failed"); return; } var reader = new StreamReader(message.Body, Encoding.GetEncoding("iso-2022-jp")); Console.WriteLine(reader.ReadToEnd()); message.Dispose(); // DELEコマンドでメッセージを削除マーク済みにする if (session.Dele(message.Number).Failed) { Console.Error.WriteLine("DELE failed"); return; } // QUITコマンドでメッセージを削除してログアウト if (session.Quit().Failed) { Console.Error.WriteLine("QUIT failed"); return; } } } }