Adsense_top

2010年2月3日水曜日

C# POP3サーバーからメールを受信する

今日は、POP3でメールボックス内の全てのメールを受信し、メールボックスから削除します。
前回書いた分は、大文字・小文字のタイプミスなどありました。すみませんでした。
重複する説明になる部分が出てくると思いますが、軽く流して下さい。
あっちこっち飛ぶと分かりにくいと思いますので、メソッドに割らないでダラダラ書いていきます。


カッコ等も省かず書きますので、コードをすべてまとめると、一つのメソッドになります。
/// 
/// POP3サーバのすべてのメールを受信しサーバより削除します。
///

/// POP3サーバ名
/// ポート番号
/// ユーザー名(アカウント)
/// パスワード
public void ReceiveAll(string host, int port,
string user, string pass)
{
string result;
Stream stream = null;
TcpClient tcp;
tcp = new TcpClient();
try
{
// 接続
tcp.Connect(host, port);
// NetworkStreamを得る
stream = tcp.GetStream();
// タイムアウト時間の設定
stream.ReadTimeout = 30 * 1000;
stream.WriteTimeout = 30 * 1000;
// StreamReader、StreamWriterを被せる
StreamReader reader =
new StreamReader(stream, Encoding.ASCII);
StreamWriter writer =
new StreamWriter(stream, Encoding.ASCII);
// 改行文字とバッファフラッシュを設定
writer.NewLine = "\r\n";
writer.AutoFlush = true;
// サーバーからの挨拶コードを得る
result = reader.ReadLine();
if (!result.StartsWith("+OK"))
throw new Exception(string.Format("エラー応答:{0}",result));
// USERコマンド
writer.WriteLine("USER {0}", user);
result = reader.ReadLine();
if (!result.StartsWith("+OK"))
throw new Exception(string.Format("エラー応答:{0}",result));
// PASSコマンド
writer.WriteLine("PASS {0}", pass);
result = reader.ReadLine();
if (!result.StartsWith("+OK"))
throw new Exception(string.Format("エラー応答:{0}",result));

ここまでは前回とほぼ同じです。
サーバーに接続し USER 、PASS コマンドでログインしています。
"+OK"とあるのは、POP3サーバーでは、正常にコマンドが実行された場合には「+OK」、異常がある場合には「-ERR」を先頭しにして応答する為、正常応答かを確認しています。


    // 一覧を取得(LISTコマンド)
writer.WriteLine("LIST");
result = reader.ReadLine();
if (!result.StartsWith("+OK"))
throw new InvalidDataException(
string.Format("エラー応答:{0}", result));
// 「.」が出てくるまでループして一覧番号(UID)を取得
List uidList = new List();
while ((result = reader.ReadLine()) != ".")
{
// [UID サイズ]の形式で返ってくるので、UIDのみリストとして取得
string[] val = result.Split(new Char[] { ' ' });
uidList.Add(int.Parse(val[0]));
}

ここでは、LISTコマンドでメールボックス内のメールのリストを取得しています。
各メールに振られている UID(ユニークな識別番号)の一覧をとしてListに格納しています。


    StringBuilder builder = new StringBuilder();
foreach (int uid in uidList)
{
builder.Length = 0;
// メールを取りだす(RETRコマンド)
writer.WriteLine(string.Format("RETR {0}", uid));
result = reader.ReadLine();
if (!result.StartsWith("+OK"))
throw new InvalidDataException(
string.Format("エラー応答:{0}", result));
// メール終端までループして受信
while (true)
{
if ((result = reader.ReadLine()) == ".")
{
// "." のみの場合はメールの終端を表す
break;
}
builder.Append(result);
builder.Append("\r\n");
}
// ここではコンソールに出力
Console.WriteLine(builder.ToString());

メール受信の部分です。
先に取得した UID を RETRコマンド の引数として送る事により、対象のメールを要求します。
whileループしている部分で、メールを受信しています。コメントに書いている通り、「.」(ピリオド)のみの行がメールの終端を表していますので、出現するでループしています。


      // 削除フラグを送信(DELEコマンド)
// 実際の削除は QUITコマンドにて行われる。
writer.WriteLine(string.Format("DELE {0}", uid));
result = reader.ReadLine();
if (!result.StartsWith("+OK"))
throw new Exception("エラー応答:{0}", result));
}

DELEコマンドに引数として UID を付けて送る事により、受信を完了したメールに削除フラグを付けています。
削除フラグと書いたのは、この後の QUIT を送る事により削除が実行されるからです。
QUITを送る前に何らかの理由で切断した場合は、メールは削除されません。


    // ログアウト(QUITコマンド)
writer.WriteLine("QUIT");
result = reader.ReadLine();
if (!result.StartsWith("+OK"))
throw new Exception(string.Format("エラー応答:{0}",result));
}
finally
{
if (stream != null)
stream.Close();
if (tcp != null && tcp.Connected)
tcp.Close();
}
}

QUIT コマンドでログアウトしています。先に書いたように、DELE コマンドで削除を指定したメールは正常にログアウトした時点で、削除された事になります。



メール受信に関するネタはもう少し続くと思います。


0 件のコメント:

コメントを投稿