其基本原理如下:
一开始便是客户端与服务器的连接。不过,在客户端连接到服务器之前,注意把端口设为POP3协议默认的110号。
客户端连接服务器成功后,服务器会返回以下信息:
+OK……
字符+OK是POP3协议的返回信息。它的回应信息不像SMTP协议那样用丰富多变的数字表示,只有两个:+OK或者-ERR。其中,+OK表示连接成功,而-ERR则表示连接失败。
接下来,客户端输入USER <用户名>
该命令告诉服务器你的用户名。注意,有些服务器会区分大小写字母的。
服务器返回+OK后,客户端输入PASS <口令>
服务器返回+OK后,还返回一些邮箱的统计信息,比如:+OK 1 message(s) [1304 byte(s)]
不同的服务器返回的信息格式不太一样,所以我们可以用STAT命令来查看邮箱的情况。STAT命令的回应中有两个数字,分别表示邮件的数量和邮件的大小。
如果信箱里有信,就可以用RETR命令来获取邮件的正文。RETR命令的格式为:
RETR <邮件编号>
如果返回结果第一行是+OK信息,则表示成功。第二行起便是邮件的正文。最后一行和SMTP协议一样,是一个单独的英文句号,表示邮件的结尾部分。
把邮件存储起来后要用DELE命令删除邮箱中的邮件,否则原有的邮件会继续保留在服务器上,一旦邮件一多,你的邮箱就爆了。DELE命令的格式为:
DELE <邮件编号>
如果删错了,可以用RSET命令来恢复所有已被删除的邮件。条件是你还没有退出,一旦退出,那就一切Bye Bye了。全部完成以后,输入QUIT命令就可以退出POP3服务器了。
在了解了邮件接收的基本原理的基础上,我就向大家介绍ReceiveMessage()方法的具体实现:
根据邮件接收的基本原理和代码中的注释,我想读者应该不难读懂上面的代码。不过下面几点仍得说明:其中的CRLF为"/r/n",它的作用是在每个命令后面加上一个换行符。另外,在该方法的一开始处有一句:lock(this),它的作用是避免线程冲突。考虑到接收邮件的过程比较漫长而且占用的资源较多,所以在设计的时候我用到了多线程(有关多线程的资料读者可参考相关的书籍或文章,此处不再赘述)。在实际的程序中,上面的方法其实被另一个方法ReceiveMessageAsync()作为一个单独的线程调用。方法如下:
最后,在ReceiveMessge()方法的末尾处,它调用了事件处理函数OnMailReceived()。在C#中,事件的声明是用代表完成的,首先我们在Pop3类的开始处进行声明如下:
接着,就进行事件的声明:
这样,只要在应用程序中调用了OnMailReceived()事件,在邮件接收成功后,OnMailReceived()事件就会被触发。
到此为止,我们已经完成了核心类-Pop3类的属性、方法和事件的设计,这样整个组件也就完成了(按Ctrl+Shift+B就可以生成解决方案)。不过,由于是组件,所以不可以直接运行,我们必须做一个测试程序来测试之。下面我就用该组件做了一个简单的邮件信史,它可以向用户报告邮箱中的新邮件数目。
一开始便是客户端与服务器的连接。不过,在客户端连接到服务器之前,注意把端口设为POP3协议默认的110号。
客户端连接服务器成功后,服务器会返回以下信息:
+OK……
字符+OK是POP3协议的返回信息。它的回应信息不像SMTP协议那样用丰富多变的数字表示,只有两个:+OK或者-ERR。其中,+OK表示连接成功,而-ERR则表示连接失败。
接下来,客户端输入USER <用户名>
该命令告诉服务器你的用户名。注意,有些服务器会区分大小写字母的。
服务器返回+OK后,客户端输入PASS <口令>
服务器返回+OK后,还返回一些邮箱的统计信息,比如:+OK 1 message(s) [1304 byte(s)]
不同的服务器返回的信息格式不太一样,所以我们可以用STAT命令来查看邮箱的情况。STAT命令的回应中有两个数字,分别表示邮件的数量和邮件的大小。
如果信箱里有信,就可以用RETR命令来获取邮件的正文。RETR命令的格式为:
RETR <邮件编号>
如果返回结果第一行是+OK信息,则表示成功。第二行起便是邮件的正文。最后一行和SMTP协议一样,是一个单独的英文句号,表示邮件的结尾部分。
把邮件存储起来后要用DELE命令删除邮箱中的邮件,否则原有的邮件会继续保留在服务器上,一旦邮件一多,你的邮箱就爆了。DELE命令的格式为:
DELE <邮件编号>
如果删错了,可以用RSET命令来恢复所有已被删除的邮件。条件是你还没有退出,一旦退出,那就一切Bye Bye了。全部完成以后,输入QUIT命令就可以退出POP3服务器了。
在了解了邮件接收的基本原理的基础上,我就向大家介绍ReceiveMessage()方法的具体实现:
/// /// 接收邮件信息 /// public void ReceiveMessage() { // 避免线程冲突 lock(this) { // 设置初始连接 con = new Pop3Connection(); if(port <= 0) port = 110; con.Open(host, port); StringBuilder buf = new StringBuilder(); string response; int code; // 获取欢迎信息 con.GetReply(out response, out code); status += response; //登录服务器过程 buf.Append("USER"); buf.Append(username); buf.Append(CRLF); con.SendCommand(buf.ToString()); con.GetReply(out response, out code); status += response; buf.Length = 0; buf.Append("PASS"); buf.Append(password); buf.Append(CRLF); con.SendCommand(buf.ToString()); con.GetReply(out response, out code); status += response; //向服务器发送STAT命令,从而取得邮箱的相关信息:邮件数量和大小 buf.Length = 0; buf.Append("STAT"); buf.Append(CRLF); con.SendCommand(buf.ToString()); con.GetReply(out response, out code); status += response; //将总邮件数和邮件大小分离 string[] TotalStat = response.Split(new char[] {' '}); numofmails = Int32.Parse(TotalStat[1]); totalsize = (double)Int32.Parse(TotalStat[2]); for( int x = 0; x < numofmails; ++x) { //根据邮件编号从服务器获得相应邮件 buf.Length = 0; buf.Append("RETR"); buf.Append(x.ToString()); buf.Append(CRLF); con.SendCommand(buf.ToString()); con.GetReply(out response, out code); if(response[0]!='-') { //不断地读取邮件内容,只到结束标志:英文句号 while(response!=".") { body += response; con.GetReply(out response, out code); } } else status += response; } //向服务器发送QUIT命令从而结束和POP3服务器的会话 buf.Length = 0; buf.Append("QUIT"); buf.Append(CRLF); con.SendCommand(buf.ToString()); con.GetReply(out response, out code); status += response; con.Close(); // 邮件接收成功后触发的事件 if(OnMailReceived != null) { OnMailReceived(); } } } |
根据邮件接收的基本原理和代码中的注释,我想读者应该不难读懂上面的代码。不过下面几点仍得说明:其中的CRLF为"/r/n",它的作用是在每个命令后面加上一个换行符。另外,在该方法的一开始处有一句:lock(this),它的作用是避免线程冲突。考虑到接收邮件的过程比较漫长而且占用的资源较多,所以在设计的时候我用到了多线程(有关多线程的资料读者可参考相关的书籍或文章,此处不再赘述)。在实际的程序中,上面的方法其实被另一个方法ReceiveMessageAsync()作为一个单独的线程调用。方法如下:
/// /// 通过一个独立的线程接收邮件 /// public void ReceiveMessageAsync() { new Thread(new ThreadStart(ReceiveMessage)).Start(); } |
最后,在ReceiveMessge()方法的末尾处,它调用了事件处理函数OnMailReceived()。在C#中,事件的声明是用代表完成的,首先我们在Pop3类的开始处进行声明如下:
public delegate void MailReceivedDelegate(); |
接着,就进行事件的声明:
public event MailReceivedDelegate OnMailReceived; |
这样,只要在应用程序中调用了OnMailReceived()事件,在邮件接收成功后,OnMailReceived()事件就会被触发。
到此为止,我们已经完成了核心类-Pop3类的属性、方法和事件的设计,这样整个组件也就完成了(按Ctrl+Shift+B就可以生成解决方案)。不过,由于是组件,所以不可以直接运行,我们必须做一个测试程序来测试之。下面我就用该组件做了一个简单的邮件信史,它可以向用户报告邮箱中的新邮件数目。