SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

.NETでPOPサーバからメールを受信する方法

POPサーバからのメールの取得と解釈


  • X ポスト
  • このエントリーをはてなブックマークに追加

ダウンロード ソースファイル (63.4 KB)

POPでメールを受信する手順

 サンプルソースコードに含まれるPopClientクラスは、POPを使用してメールサーバからメールを受信するクラスです。以下、主要部分について解説します。

1. POPサーバとの接続

 POPサーバは通常TCPの110番ポートで待ち受けしています。そこにTcpClientで接続します。この処理はPopClientのコンストラクタで行われています。

POPサーバへ接続(C#)
public PopClient(string hostname, int port)
{
    // サーバと接続
    this.tcp = new TcpClient(hostname, port);
    this.reader = new StreamReader(this.tcp.GetStream(), Encoding.ASCII);

    // オープニング受信
    string s = ReadLine();
    if (!s.StartsWith("+OK"))
    {
        throw new PopClientException(
            "接続時に POP サーバが \"" + s + "\" を返しました。");
    }
}
POPサーバへ接続(VB.NET)
Public Sub New(ByVal hostname As String, ByVal port As Integer)
    ' サーバと接続
    Me.tcp = New TcpClient(hostname, port)
    Me.reader = New StreamReader(Me.tcp.GetStream(), Encoding.ASCII)

    ' オープニング受信
    Dim s As String = ReadLine()
    If Not s.StartsWith("+OK") Then
        Throw New PopClientException( _
            "接続時に POP サーバが """ & s & """ を返しました。")
    End If
End Sub

 上記のReadLine()メソッドは行末までの1行を読み込むprivateメソッドです。POPでは8bit ASCIIでやり取りが行われます(メールがどんな文字コードで書かれているかではなく、POP自体のやり取りのことです)。そのため、Encoding.ASCIIを指定したStreamReaderをあらかじめ作成しておいて、テキストの読み込みに使用しています。なお、POPでの行末は必ずCR LF(C#での"\r\n")と決められています。また、ReadLine()メソッドは動作確認用に受信したテキストをコンソールに書き出すようにもなっています。

 POPサーバに接続すると最初にオープニングのテキストが1行送られてきます。オープニングのテキストの最初は"+OK"で始まります。最短の場合はこの3文字と改行だけの場合もありますが、多くの場合は"+OK POP3 server ready."のようなテキストが返されます。"+OK"より後ろの部分のテキストには特に意味はありません。POPサーバの名称やバージョンが記述されていることが多いようです。POPサーバに問題があるために使用できない場合などは、受信テキストの先頭が"+OK"以外("-ERR")になります。そのため、上記のように先頭が"+OK"でない場合は例外を投げるようにしています。

 なお、サンプルソースコードではs.StartsWith("+OK")としていますが、必ずしも大文字であるとは限りません。ですからs.ToUpper().StartsWith("+OK")のような判定を行った方が汎用性が増します。以下のログインやリストの取得などPOPサーバから返されるリザルト文字列はすべて同様のことが言えますのでご注意ください。

2. ログイン

 POPサーバを使用するには、通常ユーザー名、パスワードを使用してログインする必要があります。Login()メソッドにてログイン処理を行っています。

ログイン(C#)
public void Login(string username, string password)
{
    // ユーザー名送信
    SendLine("USER " + username);
    string s = ReadLine();
    if (!s.StartsWith("+OK"))
    {
        throw new PopClientException(
            "USER 送信時に POP サーバが \"" + s + "\" を返しました。");
    }

    // パスワード送信
    SendLine("PASS " + password);
    s = ReadLine();
    if (!s.StartsWith("+OK"))
    {
        throw new PopClientException(
            "PASS 送信時に POP サーバが \"" + s + "\" を返しました。");
    }
}
ログイン(VB.NET)
Public Sub Login(ByVal username As String, ByVal password As String)
    ' ユーザー名送信
    SendLine("USER " & username)
    Dim s As String = ReadLine()
    If Not s.StartsWith("+OK") Then
        Throw New PopClientException( _
            "USER 送信時に POP サーバが """ & s & """ を返しました。")
    End If

    ' パスワード送信
    SendLine("PASS " & password)
    s = ReadLine()
    If Not s.StartsWith("+OK") Then
        Throw New PopClientException( _
            "PASS 送信時に POP サーバが """ & s & """ を返しました。")
    End If
End Sub

 SendLine()メソッドは引数のテキストに改行(CR LF。C#での"\r\n")を付加して送信するprivateメソッドです。送信時も8bit ASCIIにするため、Encoding.ASCII.GetBytes()を使用して変換した後に送信するようにしています。また、SendLine()メソッドは動作確認用に、送信するテキストをコンソールに書き出すようにもなっています。

 ログインするには、まずUSERコマンドでユーザー名を送信します。このコマンドは最初に"USER"、半角スペース、続けてユーザー名、最後に改行(CR LF)という書式になっています。「ユーザー名」の前は半角スペースを空けてください。

 例えば、ユーザー名がabc@example.comの場合は次のように送信します。

 ユーザー名が正常な場合には"+OK"で始まるテキストが返されます。オープニングのテキストと同じように"+OK"の後には"+OK username is ok."のように任意のテキストが付いてくる場合もあります。ユーザー名が正常ではないと判断された場合は"+OK"以外("-ERR")が返されます。

 次にPASSコマンドでパスワードを送信します。内容はサンプルコードを参照してください。

 このように、POPはすべてテキストのやり取りだけで構成された、とても単純で扱いやすいプロトコルです。ほとんどのやり取りは上記のUSERコマンドやPASSコマンドのように、コマンドのテキストを送信すると、それに対する返事のテキストが返ってくるという形になっています。

3. リストの取得

 POPにはメールを取得したり削除したりするコマンドがあります。POPサーバに複数のメールがたまっている場合は、どのメールを取得したり削除したりするのかを番号で指定します。この番号はあらかじめLISTコマンドで取得しておく必要があります。

リストの取得(C#)
public ArrayList GetList()
{
    // LIST 送信
    SendLine("LIST");
    string s = ReadLine();
    if (!s.StartsWith("+OK"))
    {
        throw new PopClientException(
            "LIST 送信時に POP サーバが \"" + s + "\" を返しました。");
    }

    // サーバにたまっているメールの数を取得
    ArrayList list = new ArrayList();
    while (true)
    {
        s = ReadLine();
        if (s == ".")
        {
            // 終端に到達
            break;
        }
        // メール番号部分のみを取り出し格納
        int p = s.IndexOf(' ');
        if (p > 0)
        {
            s = s.Substring(0, p);
        }
        list.Add(s);
    }
    return list;
}
リストの取得(VB.NET)
Public Function GetList() As ArrayList
    ' LIST 送信
    SendLine("LIST")
    Dim s As String = ReadLine()
    If Not s.StartsWith("+OK") Then
        Throw New PopClientException( _
            "LIST 送信時に POP サーバが """ & s & """ を返しました。")
    End If

    ' サーバにたまっているメールの数を取得
    Dim list As ArrayList = New ArrayList
    Do While True
        s = ReadLine()
        If s = "." Then
            ' 終端に到達
            Exit Do
        End If
        ' メール番号部分のみを取り出し格納
        Dim p As Integer = s.IndexOf(" "c)
        If p > 0 Then
            s = s.Substring(0, p)
        End If
        list.Add(s)
    Loop
    Return list
End Function

 番号のリストを取得するには、まずLISTコマンドを送信します。LISTコマンドには引数はないため、単に"LIST"と改行のみを送信するだけです。問題がなければPOPサーバは次のような一連のテキストを返します。

 他のコマンドと同様に"+OK"で始まる1行のテキストを返します。通常は"+OK"の後に半角スペースで区切ってPOPサーバにたまっているメールの数が記述されています。この例では、メールの数は3通だったことが分かります。何か問題があってリストを返せない場合は"-ERR"になります。

 "+OK"行の下に続いているのがメールのリストで、POPサーバにたまっているメールの数と同じ行数あります。それぞれの行頭にメールの番号があり、半角スペースで区切ってオプションのテキストが続きます(半角スペース以降がない場合もあります)。リストの最後は"."(ピリオド)のみの行となります。

 メールの番号は現在のセッション中だけ有効となります。上記の例では1番、201番、202番のメールがあることになりますが、現在のセッションを切断し、再び接続したときに同じ番号のメールがあるかどうかは分かりませんし、たとえあったとしても同じメールであるとは限りません。ですから、POPサーバに接続するたびにLISTコマンドで番号を取得する必要があります。

 今回のサンプルコードでは、取得した番号のリストをArrayListに格納して返すようにしています。

4. メールの取得

 さて、メールの番号が分かればメール本体を取得することができます。メール本体を取得するにはRETRコマンドを使用します。

メールの取得(C#)
public string GetMail(string num)
{
    // RETR 送信
    SendLine("RETR " + num);
    string s = ReadLine();
    if (!s.StartsWith("+OK"))
    {
        throw new PopClientException(
            "RETR 送信時に POP サーバが \"" + s + "\" を返しました。");
    }

    // メール取得
    StringBuilder sb = new StringBuilder();
    while (true)
    {
        s = ReadLine();
        if (s == ".")
        {
            // "." のみの場合はメールの終端を表す
            break;
        }
        sb.Append(s);
        sb.Append("\r\n");
    }
    return sb.ToString();
}
メールの取得(VB.NET)
Public Function GetMail(ByVal num As String) As String
    ' RETR 送信
    SendLine("RETR " & num)
    Dim s As String = ReadLine()
    If Not s.StartsWith("+OK") Then
        Throw New PopClientException( _
            "RETR 送信時に POP サーバが """ & s & """ を返しました。")
    End If

    ' メール取得
    Dim sb As StringBuilder = New StringBuilder
    Do While True
        s = ReadLine()
        If s = "." Then
            ' "." のみの場合はメールの終端を表す
            Exit Do
        End If
        sb.Append(s)
        sb.Append(vbcrlf)
    Loop
    Return sb.ToString()
End Function

 RETRコマンドは「"RETR"+半角スペース+LISTコマンドで取り出したメールの番号のうちの1つ+改行」というテキストを送信します。POPサーバから返ってくるテキストは"+OK"の行、メール本体、"."のみの行となります。

 メール本体はSMTPで配送されているそのままの形です。この形式は通常のテキスト形式のメールとほとんど同じです。唯一の注意点は行頭に"."(ピリオド)がある場合は".."(ピリオド2つ)となっています。メール本体の詳細は後述します。

5. メールの削除

 POPではメールを取得しても自動的に削除されることはありません。メールを削除する場合はDELEコマンドで明示的に削除する必要があります。

メールの削除(C#)
public void DeleteMail(string num)
{
    // DELE 送信
    SendLine("DELE " + num);
    string s = ReadLine();
    if (!s.StartsWith("+OK"))
    {
        throw new PopClientException(
            "DELE 送信時に POP サーバが \"" + s + "\" を返しました。");
    }
}
メールの削除(VB.NET)
Public Sub DeleteMail(ByVal num As String)
    ' DELE 送信
    SendLine("DELE " & num)
    Dim s As String = ReadLine()
    If Not s.StartsWith("+OK") Then
        Throw New PopClientException( _
            "DELE 送信時に POP サーバが """ & s & """ を返しました。")
    End If
End Sub

 メールを削除するときは「"DELE"+半角スペース+LISTコマンドで取り出したメールの番号のうちの1つ+改行」というテキストを送信します。なお、削除したメールを元に戻すことはできませんのでご注意ください。

6. クローズ

 POPとの接続を切断する際にはQUITコマンドを使用します。DELEコマンドによるメールの削除などはQUITコマンドを発行して初めて有効になるとRFCでは既定されています。ですので、切断時には必ずQUITコマンドを発行するようにすべきです(初稿では「いきなりTCPのセッションを切断しても問題は出ないと思う」と記述していましたが誤りでした。訂正させて頂きます)。

クローズ(C#)
public void Close()
{
    // QUIT 送信
    SendLine("QUIT");
    string s = ReadLine();
    if (!s.StartsWith("+OK"))
    {
        throw new PopClientException(
            "QUIT 送信時に POP サーバが \"" + s + "\" を返しました。");
    }

    ((IDisposable)this.reader).Dispose();
    this.reader = null;
    ((IDisposable)this.tcp).Dispose();
    this.tcp = null;
}
クローズ(VB.NET)
Public Sub Close()
    ' QUIT 送信
    SendLine("QUIT")
    Dim s As String = ReadLine()
    If Not s.StartsWith("+OK") Then
        Throw New PopClientException( _
            "QUIT 送信時に POP サーバが """ & s & """ を返しました。")
    End If

    CType(Me.reader, IDisposable).Dispose()
    Me.reader = Nothing
    CType(Me.tcp, IDisposable).Dispose()
    Me.tcp = Nothing
End Sub

次のページ
PopClientクラスの使用例

修正履歴

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

青柳 臣一(アオヤギ シンイチ)

Twiter: https://twitter.com/ShinichiAoyagi中学生のころにプログラミングの楽しさを知り、それ以来趣味として仕事としてプログラミングに関わるようになる。23才のときに株式会社ディーバを設立。CADソフトウエア、給水設備監視システムなどのオリジナルソフトの開発、また、さま...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/477 2006/10/03 10:18

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング