.net column
.NET開発者のためのブログメディア

C#でメール受信する方法を解説!

 
C#でメール受信する方法を解説!
基本情報技術者試験の試験対策はこちら>>

SE
C#でもメールを受信できると聞きました。具体的にどんな方法がありますか?

PM
では、実際のソースを見ながら学んでいきましょう。

C#によるメール受信とは


メールの受信に限らずサーバー間の通信を行うには、プロトコルという決まりに従う必要があります。メール送信にはSMTP、メール受信にはPOPというプロトコルを使用します。C#の.Net FrameworkにはSmtpClientというクラスがあるので送信は簡単に行えます。

ところがC#にはPOP用のクラスがないのです。そのためメール受信するにはPOPに従って通信を行う処理を自作する必要があります。この記事ではC#によるシンプルなPOP通信を解説するので、是非これを読んでメール受信ができるようになってください。

メール受信をするMainメソッド

C#によるメール受信をするサンプルのMainメソッドは以下の通りです。次の項で順次説明しましょう。

using System;
using System.IO;
using System.Text;
using System.Net.Sockets;

public static void Main()
{
using (TcpClient tc = new TcpClient())
{
// 接続
tc.ReceiveTimeout = 5000;
tc.SendTimeout = 5000;
tc.Connect(“(サーバ名)”, 110);
NetworkStream st = tc.GetStream();
Receive(st,false);

// ログイン
Send(st, “USER (ユーザ名)\r\n”);
Receive(st,false);
Send(st, “PASS (パスワード)\r\n”);
Receive(st,false);
// STATで受信メール数を確認
Send(st, “STAT\r\n”);
string str = Receive(st,false);
int cnt = int.Parse(str.Split(‘ ‘)[1]);
//メールを全て受信
for (int i = 0; i < cnt; i++)
{
// RETRでメールの中身を取得
Send(st, “RETR ” + (i+1).ToString() + “\r\n”);
Receive(st, true);
}
// QUITを送信して終了
Send(st, “QUIT\r\n”);
Receive(st, false);
}
}

TcpClientクラスで接続する

それではこのC#サンプルを説明しましょう。まず、

using (TcpClient tc = new TcpClient())

としていますが、これでTCP通信を確立します。usingは、{}で囲まれた処理が終わると自動的にTcpClientのCloseメソッドを呼び出してくれます。次の、

tc.ReceiveTimeout = 5000;
tc.SendTimeout = 5000;

は、送受信のタイムアウト時間を設定しています。5000は5千ミリ秒、つまりサーバの通信の応答を5秒待つということです。それを過ぎると通信失敗と判断して例外が発生し、プログラムが中断します。

接続して応答を確認する

次の、

tc.Connect(“(サーバ名)”, 110);

はサーバー名(xxx.comやxxx.co.jp等)とポート番号を指定します。このC#サンプルを実際試す場合は、受信メールが消えても良いような適当なフリーメールアドレスで試してください。

NetworkStream st = tc.GetStream();
Receive(st,false);

で最初の通信を行っています。このReceiveというメソッドの中身は後で掲載します。今は受信を行っているんだな、くらいに理解しておいてください。Receiveではサーバからの応答を表示していますが、以下のようにコンソールに出てきます。

S:+OK Hello there.

ユーザ名とパスワードを送信する

次にユーザ名とパスワードを送信します。メールのユーザ名はメールアドレスと同じであることが多いですね。

Send(st, “USER (ユーザ名)\r\n”);
Receive(st,false);
Send(st, “PASS (パスワード)\r\n”);
Receive(st,false);

Sendというメソッドについても後で説明します。この部分が実行されると以下のように表示されます。

C:USER (ユーザー名)
S:+OK Password required.
C:PASS (パスワード)
S:+OK Connected to proxy server.

このような通信のやり取りを「プロトコル」と言うのです。

STATでメールの件数を確認する

次の、

Send(st, “STAT\r\n”);
str = Receive(st,false);
int cnt = int.Parse(str.Split(‘ ‘)[1]);

でSTATというコマンドをサーバに送信して、サーバにあるメール件数を取得しています。この処理を実行するとコンソールに以下のように表示されます。

C:STAT
S:+OK 2 6942

この場合、サーバにメールが2件あってサイズは6942byteという意味です。splitで2を取り出してcntという変数に入れています。

RETRでメールの中身を取得

次にcntの数だけメール受信を行います。RETRコマンドでメールの中身を取得できます。

for (int i = 0; i < cnt; i++)
{
// RETRでメールの中身を取得
Send(st, “RETR ” + (i+1).ToString() + “\r\n”);
Receive(st, true);
}

これを実行すると、

C:RETR 1
S:+OK 3449 octets follow.
(1つ目のメールの内容)
C:RETR 2
S:+OK 3493 octets follow.
(2つ目のメールの内容)

のように表示されます。3449と3493はメール受信したデータのバイト数です。

QUITとDELEについて

最後はQUITコマンドをサーバに送信してメール受信を終了します。

Send(st, “QUIT\r\n”);
Receive(st, false);

コンソールには以下のように表示されます。

C:QUIT
S:+OK Bye-bye.

なおこのC#サンプルはサーバのメールを読み取っているだけですが、同時にサーバのメールを削除したい場合は、forループのRETR処理の後に以下を追加すれば削除されます。

Send(st, “DELE ” + (i+1).ToString() + “\r\n”);
Receive(st, false);

Receiveメソッドについて

サーバからの受信に使用するReceiveメソッドの中身は以下の通りです。

private static string Receive(NetworkStream st, bool ml)
{
byte[] data = new byte[256];
int length;
string str = “”;
MemoryStream ms = new MemoryStream();

do
{
length = st.Read(data, 0, data.Length);
ms.Write(data, 0, length);
str = Encoding.UTF8.GetString(ms.ToArray());
}
while (st.DataAvailable ||
((!ml || str.StartsWith(“-ERR”)) &&
!str.EndsWith(“\r\n”)) ||
(ml && !str.EndsWith(“\r\n.\r\n”)));

ms.Close();

if (str.StartsWith(“-ERR”))
{
Console.WriteLine(“Receive:ERROR!”);
}
Console.Write(“S:” + str);

return str;
}

Receiveメソッドの説明

Receiveメソッドの要点について説明すると、まず

private static string Receive(NetworkStream st, bool ml)

のmlはmulti lineという意味で、複数行かどうかというフラグです。RETRの時だけこれをtrueで呼び出しています。メール受信の時は複数行になるためですね。whileループを継続する条件は「DataAvailableか、1行かエラーで末尾が改行でないか、複数行で末尾が改行.改行でないか」になっています。改行.改行はPOPのルールです。

それ以外については、

str = Encoding.UTF8.GetString(ms.ToArray());

でわかるように受信したデータはUTF-8でエンコーディングしています。そのため文字コードがShift_JISなどのメールは日本語が文字化けします。

Sendメソッドの説明

送信のSendメソッドは以下の通り簡単です。

private static void Send(NetworkStream st, string str)
{
byte[] data = Encoding.ASCII.GetBytes(str);
st.Write(data, 0, data.Length);
Console.Write(“C:” + str);
}

RETRなどのコマンドの送信は先頭にC:をつけてアスキーコードで行います。POPのプロトコルでそういったルールになっているのです。

SE
まず、POPによる通信でいるようにプログラムを作成する必要があるのですね。

PM
そうです。C#を使ったメールプロトコルをぜひマスターしてください。

プロトコルを学んでより優れたメールアプリを作ろう

C#によるメール受信を簡単に説明しました。POPのプロトコルについてはRFC1939で定められていて、しっかり動作するメール受信アプリを作るにはこの記事を読むだけでなく、より勉強する必要があります。メールプロトコルをマスターしてより優れたC#アプリを制作してください。


.NET分野でのキャリアアップをお考えの方は、現在募集中の求人情報をご覧ください。

また、直接のエントリーも受け付けております。

エントリー(応募フォーム)

Search

Popular

reccomended

Categories

Tags