┏第12号━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃         .NETプログラミング研究         ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜メニュー ■.NET Tips ・POP3メールサーバーからメールを受信する ■ピンポイントリンク ・C#のコードをVB.NETへ変換する(及びその逆)  前回の修正と捕捉 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜 ─────────────────────────────── ■.NET Tips ─────────────────────────────── ●POP3メールサーバーからメールを受信する .NET Frameworkでは、System.Web.Mail.SmtpMailクラスを使用すると、 簡単にメールを送信することが出来ます。多分そのために、「メール の受信も簡単に出来るのでは?」と思ったり、「メーラーを作りたい」 と思い立つ人が多いようで、「メールの受信はどうするの?」といっ た質問を多く受けるようになりました。 しかし残念ながら、メールの受信はそう簡単ではありません。POP3メー ルサーバーからメールを受信するには、今まで通り、ソケットを使っ てやり取りをする必要があります。それだけならまだしも、受信した メールを正しく解釈するには、MIMEなどのややこしい知識が要ります。 以下にTcpClientクラスを使用してPOP3メールサーバーからすべてのメー ルを受信するごく簡単な例を紹介しますが、多少まともなPOP3クライ アントを作成するつもりであれば、更なるPOP3やMIME等の知識が絶対 に必要であることを認識しておいてください。つまり、RFCの該当箇所 (「Post Office Protocol - Version 3」など)を読んで理解する必 要があります。 ・IETF RFC Page http://www.ietf.org/rfc ・Post Office Protocol - Version 3 http://www.ietf.org/rfc/rfc1939.txt もしちゃんと勉強するつもりがなく、それでもメールを受信したいと いうのであれば、COMなどに頼るのがよいでしょう。Tatsuo Babaさん のBASP21 DLLが有名で、お勧めです。 ・Baba Centerfolds http://www.hi-ho.ne.jp/babaq/index.html 以上のように初心者の方には全く勧められませんが、ごく簡単な例を 以下に紹介します。次のコードは、コンソールアプリケーションとし て、POP3サーバー(サーバー名:localhost、ポート番号:110)のメー ルボックス(ユーザー名:userid、パスワード:password)からメール を受信する(さらにメールは削除する)例です。Pop3Mailクラスの Receiveメソッドは受信したすべてのメールをstring型配列として返し ます。 //[C#]・・・・・・・・・・・・・・・・・・・・・・・・・・・・ using System; using System.Text; using System.Net.Sockets; namespace Dobon.Net.Mail { public class Pop3Mail { //エントリポイント public static void Main() { string[] mails; mails = Receive("localhost", 110, "userid", "password", true); Console.ReadLine(); } /// /// POP3サーバーからメールをすべて受信する /// /// POP3サーバー名 /// POP3サーバーのポート番号 /// ユーザーID /// パスワード /// メールを削除するか /// 取得したメールの配列 public static string[] Receive(string hostName, int portNumber, string userId, string passWord, bool deleteMails) { string[] mails; string msg = ""; NetworkStream stream; //TcpClientの作成 TcpClient client = new TcpClient(); //タイムアウトの設定 client.ReceiveTimeout = 10000; client.SendTimeout = 10000; try { //サーバーに接続 client.Connect(hostName, portNumber); //ストリームの取得 stream = client.GetStream(); //受信 msg = ReceiveData(stream); //USERの送信 SendData(stream, "USER " + userId +"\r\n"); //受信 msg = ReceiveData(stream); //PASSの送信 SendData(stream, "PASS " + passWord +"\r\n"); //受信 msg = ReceiveData(stream); //STATの送信 SendData(stream, "STAT\r\n"); //受信 msg = ReceiveData(stream); //メール数の取得 int mailsCount = int.Parse(msg.Split(' ')[1]); mails = new string[mailsCount]; //すべてのメールの内容を受信 for (int i = 1; i <= mailsCount; i++) { //RETRの送信(メール本文を受信) SendData(stream, "RETR " + i.ToString() + "\r\n"); //受信 msg = ReceiveData(stream, true); mails[i - 1] = msg.Substring(msg.IndexOf("\r\n") + 2); //メールを削除するか if (deleteMails) { //DELEの送信(メールに削除マークを付ける) SendData(stream, "DELE " + i.ToString() + "\r\n"); //受信 msg = ReceiveData(stream); } } //QUITの送信 SendData(stream, "QUIT\r\n"); //受信 msg = ReceiveData(stream); } catch { throw; } finally { //切断 client.Close(); } return mails; } //データを受信する private static string ReceiveData( NetworkStream stream, bool multiLines, int bufferSize, Encoding enc) { byte[] data = new byte[bufferSize]; int len; string msg = ""; //すべて受信する //(無限ループに陥る恐れあり) do { //受信 len = stream.Read(data, 0, data.Length); //文字列に変換する msg += enc.GetString(data, 0, len); } while (stream.DataAvailable || ((!multiLines || msg.StartsWith("-ERR")) && !msg.EndsWith("\r\n")) || (multiLines && !msg.EndsWith("\r\n.\r\n"))); //"-ERR"を受け取った時は例外をスロー if (msg.StartsWith("-ERR")) throw new ApplicationException("Received Error"); //表示 Console.Write("S: " + msg); return msg; } private static string ReceiveData(NetworkStream stream, bool multiLines, int bufferSize) { return ReceiveData(stream, multiLines, bufferSize, Encoding.GetEncoding(50220)); } private static string ReceiveData(NetworkStream stream, bool multiLines) { return ReceiveData(stream, multiLines, 256); } private static string ReceiveData(NetworkStream stream) { return ReceiveData(stream, false); } //データを送信する private static void SendData(NetworkStream stream, string msg, Encoding enc) { //byte型配列に変換 byte[] data = enc.GetBytes(msg); //送信 stream.Write(data, 0, data.Length); //表示 Console.Write("C: " + msg); } private static void SendData(NetworkStream stream, string msg) { SendData(stream, msg, Encoding.ASCII); } } } //・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・ '[VB.NET]・・・・・・・・・・・・・・・・・・・・・・・・・・ 'C#のコードを'C# to VB.NET Translator'で変換し、修正したコードです 'http://www.aspalliance.com/aldotnet/examples/translate.aspx Imports System Imports System.Text Imports System.Net.Sockets Namespace Dobon.Net.Mail Public Class Pop3Mail 'エントリポイント Public Shared Sub Main() Dim mails() As String mails = Receive("localhost", 110, "userid", "password", True) Console.ReadLine() End Sub 'Main '/ '/ POP3サーバーからメールをすべて受信する '/ '/ POP3サーバー名 '/ POP3サーバーのポート番号 '/ ユーザーID '/ パスワード '/ メールを削除するか '/ 取得したメールの配列 Public Shared Function Receive( _ ByVal hostName As String, _ ByVal portNumber As Integer, _ ByVal userId As String, _ ByVal passWord As String, _ ByVal deleteMails As Boolean) As String() Dim mails() As String Dim msg As String = "" Dim stream As NetworkStream 'TcpClientの作成 Dim client As New TcpClient 'タイムアウトの設定 client.ReceiveTimeout = 10000 client.SendTimeout = 10000 Try 'サーバーに接続 client.Connect(hostName, portNumber) 'ストリームの取得 stream = client.GetStream() '受信 msg = ReceiveData(stream) 'USERの送信 SendData(stream, "USER " + userId + vbCrLf) '受信 msg = ReceiveData(stream) 'PASSの送信 SendData(stream, "PASS " + passWord + vbCrLf) '受信 msg = ReceiveData(stream) 'STATの送信 SendData(stream, "STAT" + vbCrLf) '受信 msg = ReceiveData(stream) 'メール数の取得 Dim mailsCount As Integer = _ Integer.Parse(msg.Split(" "c)(1)) mails = New String(mailsCount) {} 'すべてのメールの内容を受信 Dim i As Integer For i = 1 To mailsCount 'RETRの送信(メール本文を受信) SendData(stream, "RETR " + i.ToString() + vbCrLf) '受信 msg = ReceiveData(stream, True) mails((i - 1)) = _ msg.Substring((msg.IndexOf(vbCrLf) + 2)) 'メールを削除するか If deleteMails Then 'DELEの送信(メールに削除マークを付ける) SendData(stream, "DELE " + i.ToString() + vbCrLf) '受信 msg = ReceiveData(stream) End If Next i 'QUITの送信 SendData(stream, "QUIT" + vbCrLf) '受信 msg = ReceiveData(stream) Catch Finally '切断 client.Close() End Try Return mails End Function 'Receive 'データを受信する Private Overloads Shared Function ReceiveData( _ ByVal stream As NetworkStream, _ ByVal multiLines As Boolean, _ ByVal bufferSize As Integer, _ ByVal enc As Encoding) As String Dim data(bufferSize) As Byte Dim len As Integer Dim msg As String = "" 'すべて受信する '(無限ループに陥る恐れあり) Do '受信 len = stream.Read(data, 0, data.Length) '文字列に変換する msg += enc.GetString(data, 0, len) Loop While stream.DataAvailable Or _ ((Not multiLines Or msg.StartsWith("-ERR")) And _ Not msg.EndsWith(vbCrLf)) Or _ (multiLines And Not msg.EndsWith(vbCrLf + "." + vbCrLf)) '"-ERR"を受け取った時は例外をスロー If msg.StartsWith("-ERR") Then Throw New ApplicationException("Received Error") End If '表示 Console.Write(("S: " + msg)) Return msg End Function 'ReceiveData Private Overloads Shared Function ReceiveData( _ ByVal stream As NetworkStream, _ ByVal multiLines As Boolean, _ ByVal bufferSize As Integer) As String Return ReceiveData(stream, multiLines, bufferSize, _ Encoding.GetEncoding(50220)) End Function 'ReceiveData Private Overloads Shared Function ReceiveData( _ ByVal stream As NetworkStream, _ ByVal multiLines As Boolean) As String Return ReceiveData(stream, multiLines, 256) End Function 'ReceiveData Private Overloads Shared Function ReceiveData( _ ByVal stream As NetworkStream) As String Return ReceiveData(stream, False) End Function 'ReceiveData 'データを送信する Private Overloads Shared Sub SendData( _ ByVal stream As NetworkStream, _ ByVal msg As String, _ ByVal enc As Encoding) 'byte型配列に変換 Dim data As Byte() = enc.GetBytes(msg) '送信 stream.Write(data, 0, data.Length) '表示 Console.Write(("C: " + msg)) End Sub 'SendData Private Overloads Shared Sub SendData( _ ByVal stream As NetworkStream, _ ByVal msg As String) SendData(stream, msg, Encoding.ASCII) End Sub 'SendData End Class 'Pop3Mail End Namespace 'Dobon.Net.Mail '・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・ ・POP3メールサーバーからメールを受信する http://dobon.net/vb/dotnet/internet/receivepop3mail.html ─────────────────────────────── ■ピンポイントリンク ─────────────────────────────── ●C#のコードをVB.NETへ変換する(及びその逆)  前回の補足と修正 前回、C#のコードをVB.NETのコードへ、VB.NETのコードをC#のコード へ変換するのに役立つツールをいくつか紹介しましたが、今回はその 記事の修正と補足をさせていただきます。 まず前回「Convert C# to VB .NET」 http://www.kamalpatel.net/ConvertCSharp2VB.aspx に関して、 「日本語を含むコードを変換しようとすると、エラーになることがあ ります。」 と書きましたが、これは間違いのようで、実際には";"の前で改行され ている(文の途中で改行されている)とエラーが発生することがある ようです。また「Convert C# to VB .NET」の場合、エラーが発生しな くても、文の途中で改行されているコードは正しく変換されないこと が非常に多いため、「Convert C# to VB .NET」を使用する際は文の途 中で改行していないコードを入力することをお勧めします。 さらに前回は「Convert C# to VB .NET」と「C# to VB.NET Translator」 http://www.aspalliance.com/aldotnet/examples/translate.aspx のどちらが優れているか分からないと書きましたが、何度となく使っ ているうちに、「C# to VB.NET Translator」の方が圧倒的に優れてい ると感じるようになりました。 例えば上記「.NET Tips」で紹介したコードを「Convert C# to VB .NET」で変換すると、文の途中の改行を削除してから変換しても、何 十箇所と修正しなければならないほど散々な結果でした。それに比べ て「C# to VB.NET Translator」では、1つのエラーも出ることがあり ませんでした。しかし厄介なことに、do...while文の条件式で括弧の つけ方を間違えて、エラーが出なくても正常に機能しないコードにな ってしまいました。この一箇所を除けば、他は完璧に変換できたよう です。(なんとも惜しい...。) また、C#からVB.NETのコードへの変換で役に立つツールに関して、「 VBCS翻訳機」というツールがあることを教えていただきました。「 VBCS翻訳機」はsanta martaさんのフリーウェアで、「Visual Basic .NET で記述されたソースコードをVisual C# .NET に翻訳するための ツール」とのことです。 VBCS翻訳機 http://santamartaofthepeace.hp.infoseek.co.jp/products/vbcstranslator.html この「VBCS翻訳機」や前回紹介した「Convert Visual Basic .NET to C#」 http://www.ellkay.com/ConvertVB2CSharp.htm を使ってみると、正直なところ、C#からVB.NETへの変換ツールと比べ て、まだまだ実際に使用できるレベルになっていないというのが実感 です。VB.NETからC#への変換は簡単にはいかないようです。 =============================== ■このマガジンの購読、購読中止、バックナンバー、説明に関しては  次のページをご覧ください。  http://www.mag2.com/m/0000104516.htm ■発行人・編集人:どぼん!  http://dobon.net  dobon@bigfoot.com ■ご質問等はメールではなく、掲示板へお願いいたします。  http://dobon.net/bbs ■上記メールアドレスへのメールは確実に読まれる保障はありません  (スパム、ウィルス対策です)。メールは下記URLのフォームメール  から送信してください。  http://dobon.net/mail.html Copyright (c) 2003 DOBON! All rights reserved. ===============================