一个POP3客户端的C#类
作者: Bill Dean
关键词: C#, VB.NET,.NET, INTERNET
提交: 2002-02-26
更新: 2003-08-06
摘要: 本文描述的是一个实现了标准POP3命令的C#类。
· 下载源文件 - 2 Kb
· 下载演示程序- 5 Kb
· 下载VB.NET版本源文件(Ronny Reinertsen)

简介
读完Agus Kurniawan关于用C#与POP3服务器通讯的文章,我决定如果建立一个POP3客户端的类的话,我将走得更远。我决定为每一个标准的POP3命令实现方法,每一个方法返回一个包含(相应的)POP3服务器响应的字符串,某些情况命令无效,那么这些方法检查这些错误并且返回一个错误信息而不是直接发送命令到服务器。随文的源文件包含类的定义和一个使用该类与POP3邮件服务器通信的控制台演示程序(前面列出)。
类,方法和属性
随附的源代码包含一个类: POP3Client 。
POP3Client 类包含十个公用方法,其中九个代表标准的 POP3 命令:
· DELE,
· LIST,
· NOOP,
· PASS,
· QUIT,
· RETR,
· RSET,
· STAT
· and USER
每一个"POPmethods"返回一个字符串,内容为(相应的)POP3服务器响应结果,或者不恰当的命令导致的错误信息。最后一个公用方法:connect 用来初始化连结。没有实现可选的POP3命令:APOP, TOP and UIDL。
开始工作后不久,我认识到所有POP3方法应该按以下四个基本步骤实现:
1. 检查该命令载当前的POP状态中是否有效。
2. 如果有效,发送命令到服务器。
3. 读取响应结果。
4. (如果需要)改变POP状态。
我决定用一个叫state的属性来跟踪POP会话的当前状态,数据类型声明为connect_state的枚举类型。你们可以看到这些声明在类的定义的顶部。 public enum connect_state {disc,AUTHORIZATION,TRANSACTION,UPDATE}; ... public connect_state state=connect_state.disc ;
有三个POP状态:AUTHORIZATION 、TRANSACTION 、 UPDATE 。(完整的 POP3 协议定义请参见 RFC 1725)state属性在建立任何与POP3服务器的连接之前被设为disc(断开),建立连接后变为AUTHORIZATION。
I also thought it would be useful to store the user name, password, pop server name and error state (i.e.: did an error occur on the last POP3 command), so I add these properties to the class:
我也认为保存用户名、密码、POP3服务器名和错误状态是有用的(例如:判断上一个POP3命令是否发生错误),所以我在类中加入了这些属性: public string user; public string pwd; public string pop; public bool error;
连接服务器(TcpClient)、发送(NetworkStream)和接收数据(StreamReader)的机制直接取自Agus的代码。我甚至保留了相同的变量名:
private TcpClient Server; private NetworkStream NetStrm; private StreamReader RdStrm; private string Data; private byte[] szData; private string CRLF = "\r\n";
在做任何其他工作之前,我们需要建立道服务器的连接以及取得网络流中的信息。这个在connect 公用方法中进行。 public string connect() {
Server = new TcpClient(pop,110); try {
NetStrm = Server.GetStream(); RdStrm= new StreamReader(Server.GetStream());
state=connect_state.AUTHORIZATION ; return(RdStrm.ReadLine ()); } catch(InvalidOperationException err) { return("Error: "+err.ToString()); } }
注意:只要连接一初始化,会话就进入了
正如前面所提到的,九个POP3方法实质上具有相同的结构。DELE 方法的源代码展示出该结构。 public string DELE(int msg_number) { string temp; if (state != connect_state.TRANSACTION ) {
temp="Connection state not = TRANSACTION"; } else { issue_command("DELE " + msg_number.ToString ()); temp=read_single_line_response(); } return(temp); }
首先,我们知道DELE POP3命令只在TRANSACTION state DELE ifissue_command() issue_command "DELE "RFC 1725描述了DELE命令返回一个从服务器发回的单行响应,我们用方法read_single_line_response 来读取。两个方法都相当直接明了,不管是向建立连结的服务器写字符还是从建立连结的服务器读取来自于网络流的字符。因为执行完DELE命令后POP会话状态仍为TRANSACTION状态,我们没必要担心要改变state 值。state 改变的例子请参见源代码的PASS 方法。 private void issue_command(string command) {
Data= command + CRLF; szData = System.Text.Encoding.ASCII.GetBytes(Data.ToCharArray()); NetStrm.Write(szData,0,szData.Length); } private string read_single_line_response() {
string temp; try { temp = RdStrm.ReadLine(); was_pop_error(temp); return(temp); } catch(InvalidOperationException err) { return("Error in read_single_line_response(): " + err.ToString ()) ; } }
注意,在某些情况,有些POP3命令返回多行响应。这里也采用一个名叫read_multi_line_response 的方法来处理。我前面已经提到过,我认为显示地判断最后一个POP命令是否正确执行,或者POP3服务器是否返回错误,将是有用的。这里用was_pop_error 私有方法来检查。 private void was_pop_error(string response) { if(response.StartsWith ("-")) { error=true; } else { error=false; } }
使用示例
POP3协议的细节有点超出本文章的范围。所以如果你想多了解POP3的话,我建议你去RFC 1725,你可以在这里找到。让我们简单的看一下示例程序,以便了解怎样使用这个类:
static void Main(string[] args){ POP3Client.POP3client Demo = new POP3Client.POP3client(); Console.WriteLine ("****connecting to server:"); Console.WriteLine (Demo.connect ("your_pop3_server")); Console.WriteLine ("****Issuing USER"); Console.WriteLine (Demo.USER ("user_id")); Console.WriteLine ("****Issuing PASS"); Console.WriteLine (Demo.PASS ("password")); Console.WriteLine ("****Issuing STAT"); Console.WriteLine (Demo.STAT () ); Console.WriteLine ("****Issuing LIST"); Console.WriteLine (Demo.LIST () ); Console.WriteLine ("****Issuing RETR 700...this will cause the POP3 server to gack a " + "hairball since there is no message 700"); Console.WriteLine (Demo.RETR (700) );
Console.WriteLine ("****Issuing RETR 7"); Console.WriteLine (Demo.RETR (7) ); Console.WriteLine ("****Issuing QUIT"); Console.WriteLine (Demo.QUIT ()); Console.ReadLine (); }
总之,你创建一个POP3Client 类的实例,用你的POP3服务器调用connect 方法,就可以开始发送命令了。你将需要调用USER 和PASS 方法以成功登陆服务器,调用其他POP3方法之前必须取得有效的登陆信息。
我希望你们部分人发觉这篇文章是有用的。我也希望收到反馈或建议。
请大家明白该代码没有任何的保证,不管是明示还是暗示。该代码严格的“无保证”提供,仅仅为教育目的。谁使用谁负责。要使用该代码,请允诺使用该代码带来的任何损失与作者和Restek无关。
历史
- 2003-08-06 —— Ronny Reinertsen好意地把C#版本转为VB.NET
(完)
参看原文:POP3 Client as a C# Class 
|