• 検索結果がありません。

メール受信

N/A
N/A
Protected

Academic year: 2021

シェア "メール受信"

Copied!
18
0
0

読み込み中.... (全文を見る)

全文

(1)

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

.NET Framework 1.0、1.1 にはメールを送信する為の System.Web.Mail.SmtpMail クラスが用意され て居る。.NET Framework 2.0 には System.Net.Mail.SmtpClient クラスが用意されて居る(猶、2.0 にもSystem.Web.Mail.SmtpMail クラスは有るが、System.Net.Mail.SmtpClient クラスの使用が推奨 されて居る)。併し、残念乍、メールを受信するクラスは用意されて居ない。 其処で、此処では、TcpClient クラスを使用して、直接メールサーバからメールを受信する方法を解説 する。併せて、受信したメールのヘッダ部分から Subject、From、To 等のヘッダ情報を取得したり、 添付ファイルを取り出したりする方法に付いても解説する。 ■ 必要な環境

サンプルはVisual Studio.NET 2003 で作成され、.NET Framework 1.1 で動作確認をして居る。亦、 Visual Studio 2005、.NET Framework 2.0 での動作も確認して居る。

■ インターネットメールの仕組み

インターネットメールは、SMTP と呼ばれるプロトコルを使ってインターネット内を配送されて居る。 SMTP は、Simple Mail Transfer Protocol の頭文字で、文字通り単純なメール転送プロトコルと成って 居る。此処では、SMTP の詳細に付いては省略するが、SMTP は、RFC 2821 等に解説されて居る。 前述の様に、メールはSMTP を使用して配送される訳だが、SMTP に依って配送されるのは SMTP サ ーバ迄で有る。個々のユーザー迄配送する仕組みは特に無い。実世界に例えると、総てのメールは郵便 局止めに成って居て、各家庭や事務所の郵便ポスト迄は配達して下れないと謂う事に成る。其れでは何 うするかと謂うと、メールを受け取り度い人が夫々れ郵便局迄取りに行く事に成る。メーラー、メール ユーザーエージェント(Mail User Agent:MUA)等と呼ばれる Outlook Express、Outlook 2003、 Mozilla Thunderbird、Becky!と謂うインターネットメール用のソフトウェアが有るが、此等は孰れも 定期的に郵便局(メールサーバ)にメールが届いて居るか何うかを確認し、必要に応じてメールを取り に行く様に成って居る。此の時に使われるプロトコルの代表的な物がPOP で有る。POP は、Post Office Protocol の頭文字で、文字通り『郵便局プロトコル』で有る。現在一般的に使われて居る POP はバー ジョン3 と成って居るので、POP3 と表記される事も良く有る(以下、単に POP と表記するが、POP3 の事と考えて問題無い)。POP に付いては、RFC 1939 で解説されて居る。

猶、インターネットメールはSMTP と POP を使わなくては成らないと謂う訳では無い。POP より高機 能なIMAP(Internet Message Access Protocol)と謂うプロトコルも有る(RFC 2060)。亦、SMTP で配送されたメールをハードディスクにファイルと仕て保存して、其れをテキストエディタで閲覧する と謂う事も可能で有る(勿論、其の様な事が出来るメールサーバを用意する必要が有る)。 此の様に、インターネットメールの配送にSMTP が使われるのは粗確実だが、SMTP で配送された後 のメールを何の様に扱うかは非常に自由度が高い仕組みと成って居た。併し、インターネットサービス プロバイダや企業のメールサーバの様に多数の人にメールサービスを提供する場合は、統一された手法 が無いと不便なので、現在ではメールの送信にはSMTP を、メールの受信には POP を使用するのが一 般的に成って居る(勿論、Web メールと呼ばれる様な、ブラウザ上で而巳メールサービスを提供して居 る場合は除く)。亦、メーラーも粗例外無く SMTP と POP をサポートして居ると謂っても良い状況に 成って居る。

(2)

RFC とは:RFC は Request For Comment の頭文字で、インターネットに関連するさまざまな 技術の仕様等に付いてまとめられた文書の事で有る。RFC には番号が付けられていて、RFC 2821 はSMTP の仕様、RFC 2616 は HTTP の仕様等と成って居る。中には RFC 1149(鳥を使って IP データを送受信する事に関する仕様)の様にジョーク RFC も存在する。改訂版が出る場合は 新しい番号が振られて別の文書と仕て公開されるのが通常で有る。SMTP の場合、最初の RFC は 821、其の後の改訂版は 2821 と成って居る。RFC の文書は英語で書かれて居るが、主要な RFC に付いては日本語訳を公開して居る場合も有るので検索してみて下さい。 ■ メール受信時に特定の処理を行うには 特定のメールアドレスにメールが届いた時に、其のメールを自動的に受信して何等かの処理を行う様な システムを作成するには、次の様な方法が考えられる。 ・メールサーバの機能を使う。 ・メーラーの機能を使う。 ・POP で受信する。 メールサーバの機能を使う メールサーバ(正確には SMTP サーバ)には、メールが届いた時に外部プログラムを起動すると謂う 機能を持つ物が有る。此の機能を使って、メール受信時に処理を行うシステムを作成する事が出来る。 メーリングリストと謂うの物が存在するが、メーリングリストでは、或るメールアドレスにメールを送 ると、予め登録された会員全員に其のメールが自動的に配送される。此の様なメーリングリスト機能は、 メールサーバにメーリングリスト処理を行う外部プログラムを登録して実現されて居る場合が多く有 る。 此の外部プログラム起動方式は、メール受信時に直ぐ様、外部プログラムが呼び出されるのが一般的だ し、必要な時に必要な処理丈を行う様に出来る。当然、レスポンスの面でも、メールサーバに与える負 荷の面でも、優れたシステムに出来る可能性が高いと謂える。併し、外部プログラムの登録にはメール サーバの設定を変更する必要が有り、誤った外部プログラムを登録した場合は、メールサービス自体を 使用不能に陥らせる危険性も有る。此の設定変更を行うには、メールサーバの管理者か其れに匹敵する 権限が必要だし、既存のメールサーバに対して設定を行う場合は、細心の注意を仕て作業する必要が有 る。其の為、残念乍、誰にでも出来る方法とは謂えない。特にインターネットサービスプロバイダのメ ールサービスを使用して居る場合は、外部プログラムを登録する事は出来ないと考えた方が良いと思う。 此の方法の場合、上記の理由に依り、自分の管理下に有るメールサーバが必要に成る。亦、何の様な事 が出来るのか、何の様な外部プログラムを作れば良いのかは、使用するメールサーバに依り変わる。 メーラーの機能を使う メーラーに依っては、プラグインの様な形で機能を拡張・追加したり、マクロ言語が搭載されて居たり する。此等の機能を使ってメール受信時の処理を作り込む事が出来る場合が有る。旨く使えば簡単に目 的を実現出来る場合も有ると思うが、何の様な事が出来、何の様にすれば良いのかは、完全にメーラー に依存するので、此処では解説しない。 POP で受信する 本資料で解説する方法で有る。メールサーバにTCP で接続し、POP を使用してメールを受信する。此

(3)

サーバに接続出来る環境で有れば、何処でも実行する事が出来る。メーラーのメール受信処理而巳を自 分で実装して実行して居るのと変わらない。実際、メールサーバに取っては、メーラーからのアクセス と区別が付かないで有ろう。 此の方法の欠点は、即時性に欠ける事で有る。POP は、メールサーバにメールが届いて居るかを此方か ら問い合わせる様なプロトコルと成って居る。殆どのメーラーには「新着メールのチェック間隔」の様 な設定項目が有って、何の程度の間隔でメールサーバに問い合わせに行くのかを設定出来る様に成って 居る。仮に5 分とすると、メールが送られて来てから最大 5 分は遅延する事に成る。間隔を短くすれば 即時性は高まるが、極端に短い間隔にすると、メールサーバの負荷を高める事にも成り兼ねないので避 けた方が良い。 インターネットメールは、元々即時性が保障された仕組みでは無い。メールが直ぐに届く事も有るが、 少し時間が懸かる事も普通に有る。従って、此の即時性に欠けると謂う点は、余り問題に成らない事が 多いかと思う。逆に問題に成る様な場合は、メールを使うと謂う事自体を見直す必要が有る。 ■ POP でメールを受信する手順 サンプルソースコードに含まれる PopClient クラスは、POP を使用してメールサーバからメールを受 信するクラスで有る。以下、主要部分に付いて解説する。 1. POP サーバとの接続 POP サーバは、通常 TCP の 110 番ポートで待ち受けして居る。其処に TcpClient で接続する。此の処 理は、PopClient のコンストラクタで行われて居る。 Visual Basic

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

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 + "¥" を返しました。"); }

(4)

上記の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( ) メソッドにてログイン処理を行って居る。 Visual Basic

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

C# public void Login(string username, string password) { // ユーザー名送信 SendLine("USER " + username); string s = ReadLine( ); if (!s.StartsWith("+OK")) {

throw new PopClientException(

"USER 送信時に POP サーバが ¥"" + s + "¥" を返しました。"); }

(5)

// パスワード送信 SendLine("PASS " + password); s = ReadLine( ); if (!s.StartsWith("+OK")) {

throw new PopClientException(

"PASS 送信時に POP サーバが ¥"" + s + "¥" を返しました。"); }

}

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 コ マンドで取得して置く必要が有る。 Visual Basic Public Function GetList( ) As ArrayList

' LIST 送信 SendLine("LIST")

(6)

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 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;

(7)

番号のリストを取得するには、先ず LIST コマンドを送信する。LIST コマンドには引数は無い為、単 に "LIST" と改行而巳を送信する丈で有る。問題が無ければ、POP サーバは次の様な一連のテキスト を返す。 他のコマンドと同様に "+OK" で始まる 1 行のテキストを返す。通常は "+OK" の後に半角スペースで 区切ってPOP サーバに溜まって居るメールの数が記述されて居る。此の例では、メールの数は 3 通だ った事が解る。何か問題が有ってリストを返せない場合は "-ERR" に成る。 "+OK" 行の下に続いて居るのがメールのリストで、POP サーバに溜まって居るメールの数と同じ行数 有る。夫々れの行頭にメールの番号が有り、半角スペースで区切ってオプションのテキストが続く(半 角スペース以降が無い場合も有る)。リストの最後は "."(ピリオド)而巳の行と成る。 メールの番号は、現在のセッション中丈で有効と成る。上記の例では1 番、201 番、202 番のメールが 有る事に成るが、現在のセッションを切断し、再び接続した時に同じ番号のメールが有るか何うかは解 らないし、仮令有ったと仕ても、同じメールで有るとは限らない。従って、POP サーバに接続する度に LIST コマンドで番号を取得する必要が有る。 今回のサンプルコードでは、取得した番号のリストをArrayList に格納して返す様に仕て居る。 4. メールの取得 メールの番号が解れば、メール本体を取得する事が出来る。メール本体を取得するにはRETR コマンド を使用する。 Visual Basic 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

(8)

If s = "." Then ' "." 而巳の場合はメールの終端を表す Exit Do End If sb.Append(s) sb.Append(vbcrlf) Loop Return sb.ToString( ) End Function 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( ); } RETR コマンドは「"RETR"+半角スペース+LIST コマンドで取り出したメールの番号の内の 1 つ+改 行」と謂うテキストを送信する。POP サーバから返って来るテキストは "+OK" の行、メール本体、"." 而巳の行と成る。

(9)

メール本体は、SMTP で配送されて居る其の儘の形で有る。此の形式は、通常のテキスト形式のメール と殆ど同じで有る。唯一の注意点は行頭に "."(ピリオド)が有る場合は ".."(ピリオド 2 つ)と成っ て居る。メール本体の詳細は後述する。 5. メールの削除 POP ではメールを取得しても自動的に削除される事は無い。メールを削除する場合は DELE コマンド で明示的に削除する必要が有る。 Visual Basic 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

C# public void DeleteMail(string num)

{ // DELE 送信 SendLine("DELE " + num); string s = ReadLine( ); if (!s.StartsWith("+OK")) {

throw new PopClientException(

"DELE 送信時に POP サーバが ¥"" + s + "¥" を返しました。"); } } メールを削除する時は「"DELE"+半角スペース+LIST コマンドで取り出したメールの番号の内の 1 つ+改行」と謂うテキストを送信する。猶、削除したメールを元に戻す事は出来ないので注意を要する。 6. クローズ

POP との接続を切断する際には QUIT コマンドを使用する。DELE コマンドに依るメールの削除等は QUIT コマンドを発行して初めて有効に成ると RFC では既定されて居る。従って、切断時には必ず QUIT コマンドを発行する様にす可きで有る(行き成り TCP のセッションを切断するのは、問題が有 る)。

Visual Basic Public Sub Close( )

(10)

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 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; } ■ PopClient クラスの使用例

サンプルソースコードのPopMailMain クラスの PopTest( )メソッドが PopClient クラスの使用例と成 って居る。

Visual Basic ' POP サーバに接続

Dim pop As PopClient = New PopClient("POP サーバ", 110) ' ログイン

pop.Login("ユーザー名", "パスワード")

' POP サーバに溜まって居るメールのリストを取得 Dim list As ArrayList = pop.GetList( )

For i As Integer = 0 To list.Count - 1 ' メール本体を取得

Dim mail As String = pop.GetMail(CType(list(i), String)) ' メールを処理 ' メールを POP サーバから取得 pop.DeleteMail(CType(list(i), String)) Next ' 切断 pop.Close( ) C# // POP サーバに接続

(11)

PopClient pop = new PopClient("POP サーバ", 110); // ログイン

pop.Login("ユーザー名", "パスワード");

// POP サーバに溜まって居るメールのリストを取得 ArrayList list = pop.GetList( );

for (int i = 0; i < list.Count; ++i) {

// メール本体を取得

string mail = pop.GetMail((string)list[i]); // メールを処理 // メールを POP サーバから取得 pop.DeleteMail((string)list[i]); } // 切断 pop.Close( ); 此の使用例では、POP に貯まって居る総てのメールを取得して、何等かの処理を行って居る。上記の例 では、コメント而巳で何等処理も行って居ないが、本来ならメールの内容を解釈し、其れに応じて何等 かの処理を行う事に成る。添付のサンプルソースコードでは、処理する代わりに適当なファイル名で保 存する様に成って居る。 其れでは引き続きメールを解釈する方法に付いて解説する。 ■ POP から取得したメールの解釈 POP からメールを取得する事が出来たので、続いて取得したメールを解釈する。サンプルソースコード のMail クラスはメールの内容を解釈し、簡単に使用出来る様にするクラスで有る。 メールの構造 先ずは、POP サーバから受け取ったメール本体が何の様な構造に成って居るか観る事にする。猶、下記 のメールの実例(「sample1.txt」と「sample2.txt」)はサンプルソースコードと共に含めて有る。 上記は可成り単純化したメール本体の例で有る。メールは、ヘッダ部とボディ部に分かれて居る。最初 の空行迄がヘッダ部で其れ以降がボディ部で有る。上記の例では8 行目迄がヘッダ部、以降がボディ部 と成る。 メールヘッダの各項目は「項目名:内容」と謂う形式に成って居る。ヘッダ部の形式や項目の詳細に付い てはRFC 2822 等に纏められて居る。To(宛先)、From(差出人)、Subject(件名)等の様に比較的解

(12)

り易い名前が付いて居るので、大体の意味は解ると思う。通常は1 つの項目が 1 行に成るのだが、1 行 に収まり切らない場合(上記の例の Subject、Content-Type)、継続行の行頭が空白(タブか半角スペ ース)に成る。 メールボディは、メールの本文で有る。日本語のメールの場合、多くは iso-2022-jp が使われて居る。 何の様なコードが使われて居るかはヘッダ部のContent-Type の charset を参照する事に依り解る。猶、 上記の例で [ESC] と書かれて居る部分は、実際にはエスケープコード(ASCII コード 1B)で有る。 亦、本文2 行目はピリオド 2 つで始まる行で有る。POP から取得した状態では終端と間違うのを防ぐ 為にピリオド2 つに成って居る。

Content-Type の記述方法や其れに合わせたメールボディの形式は、MIME(Multipurpose Internet Mail Extensions)と呼ばれる仕様に纏められて居る。亦、上記の例の From、To、Subject には日本語 が使われて居るが、此の日本語部分の記述方法もMIME に依って決められて居る。MIME の仕様は多 岐に渡る為、主要な物丈でも次の様に複数に分かれて居る。亦、此等以外にもMIME 関連の RFC は多 数有る。 Part 1 - RFC 2045 Part 2 - RFC 2046 Part 3 - RFC 2047 Part 4 - RFC 4289 Part 5 - RFC 2049 添付ファイル 次に、メールに添付ファイルが有る場合を観る事にする。以下の例はGIF 画像が添付されて居るメール の例で有る。

(13)

此のboundary はメール毎に変わるし、形式も色々な物が有る。

boundary で分割された部分は、夫々れヘッダ部、ボディ部で構成されて居る。最初のパートは Content-Type が text/plain と成って居るので普通のテキストで有ると解る。此の部分は iso-2022-jp に エンコードされたメール本文で有る。次のパートはimage/gif と成って居て、此れが添付された GIF 画 像で有る。GIF 画像の様なバイナリファイルは、其の儘メールの本文と仕て表現する事が出来ない為、 何等かのエンコードを行う必要が有る。メールの場合は BASE64 と謂うエンコード方式を使うのが一 般的に成って居る。エンコード方式はContent-Transfer-Encoding を観ると解る。BASE64 は然程複雑 なエ ンコード方 式では無い が、.NET Framework では Convert.FromBase64String メソッド、 Convert.ToBase64String メソッドが用意されて居るので簡単に変換する事が出来る。 サンプルソースコードのMail クラスは上記の様なメール本体を受け取って解釈する。但し、メール本 体の構造は非常に柔軟性が有るし、関連するRFC も多岐に亘る。Mail クラスは、其の総てに対応して 居る訳では無い為、一部解釈出来ないメールも有るかも知れない。併し、メールの構造を理解する第一 歩には成るかと思う。 ■ Mail クラスの使用例

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

Visual Basic 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("--")

(14)

' メール本文を表示

' 本来は 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

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); } テストし易くする為に、予め保存して置いた「sample1.txt」を読み込んで、Mail クラスのインスタン スを生成して居る。本来ならPOP サーバから取得したメール本体を直接渡す事に成るかと思う。 続いてFrom、To、Subject の各ヘッダ項目をコンソールに出力して居る。mail.Header["From"] 等各 ヘッダ項目はString のコレクションに成って居る。此れは、複数の宛先に送信したメールは To が複数 に成る場合が有る等、ヘッダ項目は複数に成り得る為で有る。上記の例では、最初の要素而巳を出力し て居る。亦、全く要素数のチェック等を行って居ないが、Subject が無いメール等も有り得るので、本 来は、手を抜かずにチェックする必要が有る。

(15)

上記の出力を観ると解るが、日本語部分は "=?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」を解釈する例で 有る。

Visual Basic 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 C# private static void MailTest_Sample2( )

{

(16)

// 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 です。"); } 前半部分は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"

(17)

■ デフォルトメーラーを起動する方法 ■ デフォルトのメーラーを使用してメールの送信を行

う場合、Visual Basic 6.0 では、Microsoft MAPI Controls 6.0 を 使 用 し て 居 た 。 一 方 、 Visual Basic.NET では、Process クラスの Start メソッドを 使用して新規メール作成ウィンドウを表示する。其処 で、此処では、図1 のテキストボックス内のデータを 本文の値に設定した新規メール作成ウィンドウを表 示する方法を紹介する。

Process クラスの Start メソッドに「mailto:」で始ま る文字列を指定する事で、デフォルトのメーラーを起 動する事が出来る。メーラーの新規メール作成ウィン ドウを起動する際、「mailto:」の後に指定したメール

アドレスが宛先欄に記述される。亦、件名(subject)や本文(body)等を記述する場合、宛名(mailto: メールアドレス)の後に「?」で続けて記述する。実装コードは以下の通りで有る。

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles Button1.Click

Dim strBody As String strBody = textBox1.Text

Process.Start("mailto:Test@xxx.co.jp?subject=メーラーの起動&body=" & strBody) End Sub

リスト1

リスト1 の「Process.Start("mailto:Test@xxx.co.jp?subject=メーラーの起動&body=" & strBody)」で、 宛先(mailto:Test@xxx.co.jp)、メールの件名(subject=メーラーの起動)、本文(body=strBody:テキ

ストボックス内のデータ)の値を指定した新規メールウィンドウが表示される。上記を実装し、『メー

ラーの起動』ボタン(図1)をクリックすると図 2 が表示される。

図2

(18)

上記では、改行されたデータも、図2 の様に改行されずに表示される。此れは、新規メール作成ウィン ドウを起動する場合、総ての文字が其の儘使用出来るとは限らないからで有る。其の儘使用出来ない文 字は、文字コード表示に置き換えて使用する必要が有る。例えば、本文等で使用する「改行」は、 「%0D%0A」と謂う文字コード表示に置き換える。図 1 の様に改行されたデータを其の儘新規メール作 成ウィンドウに表示する場合、「Dim strBody As String」「strBody = textBox1.Text」を下記のコード に変更する。

Dim txtLines( ) As String Dim n As Integer

txtLines = TextBox1.Lines

For n = 0 To txtLines.GetUpperBound(0)

strBody = strBody & txtLines(n) & "%0D%0A" Next

リスト2

リスト2 を実装し、図 1 の『メーラーの起動』ボタンをクリックすると、図 3 の様に表示される。

参照

関連したドキュメント

BC107 は、電源を入れて自動的に GPS 信号を受信します。GPS

1 か月無料のサブスクリプションを取得するには、最初に Silhouette Design Store

題が検出されると、トラブルシューティングを開始するために必要なシステム状態の情報が Dell に送 信されます。SupportAssist は、 Windows

Bemmann, Die Umstimmung des Tatentschlossenen zu einer schwereren oder leichteren Begehungsweise, Festschrift für Gallas(((((),

貸借若しくは贈与に関する取引(第四項に規定するものを除く。)(以下「役務取引等」という。)が何らの

被保険者証等の記号及び番号を記載すること。 なお、記号と番号の間にスペース「・」又は「-」を挿入すること。

操作は前章と同じです。但し中継子機の ACSH は、親機では無く中継器が送信する電波を受信します。本機を 前章①の操作で

 所得税法9条1項16号は「相続…により取 得するもの」については所得税を課さない旨