SHOEISHA iD

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

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

特集記事

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

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


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

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

Mailクラスの使用例

 Mailクラスの使用例として、サンプルのソースコードのPopMailMainクラスのMailTest_Sample1()メソッド、MailTest_Sample2()メソッドを示します。MailTest_Sample1()メソッドは、添付ファイルなどがない本文テキストのみの「sample1.txt」を解釈する例です。

Mailクラスの使用例 sample1.txt(C#)
private static void MailTest_Sample1()
{
    // テストのために POP から取得する代わりにファイルから読み込みます。
    string mailtext = null;
    using (StreamReader sr = new StreamReader("sample1.txt"))
    {
        mailtext = sr.ReadToEnd();
    }

    // Mail クラスを作成します。
    Mail mail = new Mail(mailtext);

    // From、To、Subject を表示します。
    Console.WriteLine(mail.Header["From"][0]);
    Console.WriteLine(mail.Header["To"][0]);
    Console.WriteLine(mail.Header["Subject"][0]);
    Console.WriteLine("--");

    // デコードしたFrom、To、Subject を表示します。
    Console.WriteLine(MailHeader.Decode(mail.Header["From"][0]));
    Console.WriteLine(MailHeader.Decode(mail.Header["To"][0]));
    Console.WriteLine(MailHeader.Decode(mail.Header["Subject"][0]));
    Console.WriteLine("--");

    // Content-Type を表示します。
    Console.WriteLine(mail.Header["Content-Type"][0]);
    Console.WriteLine("--");

    // メール本文を表示します。
    // 本来は Content-Type の charset を参照してデコードすべきですが
    // ここではサンプルとして iso-2022-jp 固定でデコードします。
    byte[] bytes = Encoding.ASCII.GetBytes(mail.Body.Text);
    string mailbody = Encoding.GetEncoding("iso-2022-jp").GetString(bytes);

    Console.WriteLine("↓本文↓");
    Console.WriteLine(mailbody);
}
Mailクラスの使用例 sample1.txt(VB.NET)
Private Shared Sub MailTest_Sample1()
    ' テストのために POP から取得する代わりにファイルから読み込みます。
    Dim mailtext As String = Nothing
    Dim sr As StreamReader = Nothing
    Try
        sr = New StreamReader("sample1.txt")
        mailtext = sr.ReadToEnd()
    Finally
        If Not sr Is Nothing Then
            CType(sr, IDisposable).Dispose()
        End If
    End Try

    ' Mail クラスを作成します。
    Dim mymail As Mail = New Mail(mailtext)

    ' From、To、Subject を表示します。
    Console.WriteLine(mymail.Header("From")(0))
    Console.WriteLine(mymail.Header("To")(0))
    Console.WriteLine(mymail.Header("Subject")(0))
    Console.WriteLine("--")

    ' デコードしたFrom、To、Subject を表示します。
    Console.WriteLine(MailHeader.Decode(mymail.Header("From")(0)))
    Console.WriteLine(MailHeader.Decode(mymail.Header("To")(0)))
    Console.WriteLine(MailHeader.Decode(mymail.Header("Subject")(0)))
    Console.WriteLine("--")

    ' Content-Type を表示します。
    Console.WriteLine(mymail.Header("Content-Type")(0))
    Console.WriteLine("--")

    ' メール本文を表示します。
    ' 本来は Content-Type の charset を参照してデコードすべきですが
    ' ここではサンプルとして iso-2022-jp 固定でデコードします。
    Dim bytes As Byte() = Encoding.ASCII.GetBytes(mymail.Body.Text)
    Dim mymailbody As String = _
        Encoding.GetEncoding("iso-2022-jp").GetString(bytes)

    Console.WriteLine("↓本文↓")
    Console.WriteLine(mymailbody)
End Sub

 テストしやすくするために、あらかじめ保存しておいた「sample1.txt」を読み込んで、Mailクラスのインスタンスを生成しています。本来ならPOPサーバから取得したメール本体を直接渡すことになるかと思います。

 続いてFrom、To、Subjectの各ヘッダ項目をコンソールに出力しています。mail.Header["From"]など各ヘッダ項目はStringのコレクションになっています。これは、複数の宛先に送信したメールはToが複数になる場合があるなど、ヘッダ項目は複数になりうるためです。上記の例では最初の要素のみを出力しています。また、まったく要素数のチェックなどを行っていませんが、Subjectがないメールなどもありえますので、本来はきちんとチェックする必要があります。

 上記の出力を見ると分かりますが、日本語部分は"=?iso-2022-jp?B?GyRCQXc/LjxUGyhC?="のようにエンコードされたままとなっています。これをMailHeader.Decode()メソッドを使ってデコードして出力しています。

 最後にContent-Typeとボディ部のメール本文を出力しています。ボディ部もiso-2022-jpでエンコードされていますので、System.Text.Encodingクラスを使ってデコードします。例ではiso-2022-jpに決め打ちで処理していますが、本来であればContent-Typeのcharsetを参照して判断すべきです。

 続くMailTest_Sample2()メソッドは、GIFファイルが添付されている「sample2.txt」を解釈する例です。

Mailクラスの使用例 sample2.txt(C#)
private static void MailTest_Sample2()
{
    // …… 省略 ……
    
    // 1つ目のパートの Content-Type、メール本文を表示します。
    // 本来は Content-Type の charset を参照してデコードすべきですが
    // ここではサンプルとして iso-2022-jp 固定でデコードします。
    MailMultipart part1 = mail.Body.Multiparts[0];
    Console.WriteLine("パート1");
    Console.WriteLine(part1.Header["Content-Type"][0]);
    Console.WriteLine("--");

    byte[] bytes = Encoding.ASCII.GetBytes(part1.Body.Text);
    string mailbody =
        Encoding.GetEncoding("iso-2022-jp").GetString(bytes);

    Console.WriteLine("↓本文↓");
    Console.WriteLine(mailbody);
    Console.WriteLine("--");

    // 2つ目のパートの Content-Type を表示し、
    // BASE64 をデコードしてファイルとして保存します。
    // 本来は Content-Transfer-Encoding が base64 であることを確認したり、
    // Content-Type の name を参照してファイル名を決めたりすべきですが、
    // ここでは省略しています。
    MailMultipart part2 = mail.Body.Multiparts[1];
    Console.WriteLine("パート2");
    Console.WriteLine(part2.Header["Content-Type"][0]);
    Console.WriteLine("--");

    bytes = Convert.FromBase64String(part2.Body.Text);
    using (Stream stm = File.Open("sample2.gif", FileMode.Create))
    using (BinaryWriter bw = new BinaryWriter(stm))
    {
        bw.Write(bytes);
    }
    Console.WriteLine(
        "添付ファイルを保存しました。ファイル名は sample2.gif です。");
}
Mailクラスの使用例 sample2.txt(VB.NET)
Private Shared Sub MailTest_Sample2()
    ' …… 省略 ……

    ' 1つ目のパートの Content-Type、メール本文を表示します。
    ' 本来は Content-Type の charset を参照してデコードすべきですが
    ' ここではサンプルとして iso-2022-jp 固定でデコードします。
    Dim part1 As MailMultipart = mymail.Body.Multiparts(0)
    Console.WriteLine("パート1")
    Console.WriteLine(part1.Header("Content-Type")(0))
    Console.WriteLine("--")

    Dim bytes As Byte() = Encoding.ASCII.GetBytes(part1.Body.Text)
    Dim mymailbody As String = _
        Encoding.GetEncoding("iso-2022-jp").GetString(bytes)

    Console.WriteLine("↓本文↓")
    Console.WriteLine(mymailbody)
    Console.WriteLine("--")

    ' 2つ目のパートの Content-Type を表示し、
    ' BASE64 をデコードしてファイルとして保存します。
    ' 本来は Content-Transfer-Encoding が base64 であることを確認したり、
    ' Content-Type の name を参照してファイル名を決めたりすべきですが、
    ' ここでは省略しています。
    Dim part2 As MailMultipart = mymail.Body.Multiparts(1)
    Console.WriteLine("パート2")
    Console.WriteLine(part2.Header("Content-Type")(0))
    Console.WriteLine("--")

    bytes = Convert.FromBase64String(part2.Body.Text)
    Dim stm As Stream = Nothing
    Dim bw As BinaryWriter = Nothing
    Try
        stm = File.Open("sample2.gif", FileMode.Create)
        bw = New BinaryWriter(stm)
        bw.Write(bytes)
    Finally
        If Not bw Is Nothing Then
            CType(bw, IDisposable).Dispose()
        End If
        If Not stm Is Nothing Then
            CType(stm, IDisposable).Dispose()
        End If
    End Try
    Console.WriteLine( _
        "添付ファイルを保存しました。ファイル名は sample2.gif です。")
End Sub

 前半部分はMailTest_Sample1()メソッドとほとんど同様なので省略しています。

 最初に1つ目のパートをiso-2022-jpでデコードして出力しています。完全に決め打ちで処理していますが、実際にはパートの数やContent-Type、charsetの確認などが必要になります。

 続いて2つ目のパートをSystem.Convert.FromBase64String()メソッドを用いてデコードし、「sample2.gif」というファイル名で保存しています。こちらも実際にはContent-TypeやContent-Transfer-Encodingなどのチェックが必要です。

まとめ

 メールの内容を自動的にデータベースに格納するようなシステムを開発する場合、POPサーバからのメールの取得とそのメールの解釈が必要になります。そのような場合に本記事が参考になればと思います。

参考資料

 本稿の内容に関連するRFC(英文)です。

修正履歴

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

  • 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」など、さまざまなカンファレンスを企画・運営しています。

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

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

メールバックナンバー

アクセスランキング

アクセスランキング