Mailクラスの使用例
Mail
クラスの使用例として、サンプルのソースコードのPopMailMain
クラスのMailTest_Sample1()
メソッド、MailTest_Sample2()
メソッドを示します。MailTest_Sample1()
メソッドは、添付ファイルなどがない本文テキストのみの「sample1.txt」を解釈する例です。
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); }
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」を解釈する例です。
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 です。"); }
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(英文)です。
- RFC 2821 "Simple Mail Transfer Protocol"
- RFC 1939 "Post Office Protocol - Version 3"
- RFC 2060 "INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1"
- RFC 2822 "Internet Message Format"
- RFC 2045 "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies"
- RFC 2046 "Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types"
- RFC 2047 "MIME (Multipurpose Internet Mail Extensions) Part Three: Message Header Extensions for Non-ASCII Text"
- RFC 4289 "Multipurpose Internet Mail Extensions (MIME) Part Four: Registration Procedures"
- RFC 2049 "Multipurpose Internet Mail Extensions (MIME) Part Five: Conformance Criteria and Examples"