分享
 
 
 

了解POP3协议,使用简单的代码监控pop3邮箱,或者不用代码,直接使用telnet

王朝other·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

POP3协议要点 ,更详细的信息可以查看 RFC1939

(1) POP3命令由一个命令和一些参数组成。所有命令以一个CRLF对结束

(2) 命令和参数由可打印的ASCII字符组成,它们之间由空格间隔

(3) POP3响应由一个状态码和一个可能跟有附加信息的命令组成。所有响应也是由CRLF对结束

(4) 有两种状态码,"确定" ("+OK")和"失败" ("-ERR")。

(5) 当所有信息发送结束时,发送最后一行,包括一个结束字符(十进制码46,也就是".")和一个CRLF对。

(6) 在POP3协议中有三种状态,认可状态,处理状态,和更新状态。

当客户机与服务器建立联系时,一旦客户机提供了自己身份并成功确认,即由认可状态转入处理状态,在完成相应的操作后客户机发出QUIT命令,则进入更新状态,更新之后最后重返认可状态。如下图

等待连接身份确认QUIT命令

——|认可|—————|处理|——————|更新|

|__________________________________|

重返认可状态

一个最小的,成功的Client-Server会话过程

POP3 Client POP3 Server

Socket() listen()

Connect() -------------------------------> accept()

<------------------------------ +OK 发送确认消息 (进入"确认"状态)

发送USER命令------------------------------>

<----------------------------- +OK 发送确认消息

发送PASS命令------------------------------>

<----------------------------- +OK 发送确认消息 (进入"操作"状态)

发送QUIT命令------------------------------>

<----------------------------- +OK 发送确认消息 (进入"更新"状态)

如果客户在"确认"状态下发送QUIT后,会话并不进入"更新"状态

可以在命令行(cmd.exe)里测试一下:

c:\telnet pop3.163.com 110 //连接网易的邮件服务器

+OK coremail .... //服务器返回+OK

USER 'yourusername' //客户端发出用户名,可能在yourusername上需要一对单引号

PASS 'yourpassword' //客户端发出密码,可能在yourpassword上需要一对单引号

+OK mm nn // 返回邮件数和大小

STAT //得到邮箱的状态

+OK xxx xxx // 返回邮件数和大小

客户可以发出的命令列表以及含义,源自ChinaUnix

命令参数 状态描述

------------------------------------------------------------------------------------------------------------------------------

USER username认可此命令与下面的pass命令若成功,将导致状态转换

PASS password认可

APOP Name,Digest 认可Digest是MD5消息摘要,windows系统多不支持

------------------------------------------ -----------------------------------------------------------------------------------

STAT None处理 请求服务器发回关于邮箱的统计资料,如邮件总数和总字节数

UIDL [Msg#]处理 返回邮件的唯一标识符,POP3会话的每个标识符都将是唯一的

LIST [Msg#] 处理返回邮件数量和每个邮件的大小

RETR [Msg#] 处理返回由参数标识的邮件的全部文本

DELE [Msg#] 处理服务器将由参数标识的邮件标记为删除,由quit命令执行

RSET None 处理服务器将重置所有标记为删除的邮件,用于撤消DELE命令

TOP [Msg#]处理服务器将返回由参数标识的邮件前n行内容,n必须是正整数

NOOP None处理服务器返回一个肯定的响应

------------------------------------------------------------------------------------------------------------------------------

QUIT None更新

Foxmail 和 Outlook 使用 pop3时的异同 源自LinuxForum.net假定服务器上有三封邮件等待客户机接收。用foxmail与OE的不同之处在于foxmail每收一封标记删除一封,而Outlook则等全部接收完后再全部标记为删除最后执行quit命令。Foxmail OutLook

-------------------------------------------

RETR 1 RETR 1

DELE 1 RETR 2

RETR 2 RETR 3

DELE 2 DELE 1

RETR 3 DELE 2

DELE 3 DELE 3

QUIT QUIT

-------------------------------------------

简单的C#代码就可以实现pop3邮箱的监控

namespace Sky.MailMonitor

{

public class Pop3

{

private const int bufsize = 1024; //default 1kbytes buffers

//服务器确认消息的状态码,必须是大写的

private const string OKFlag = "+OK";

private const string ERRFlag = "-ERR";

private int _port = 110;

public int Port

{

get

{

return _port;

}

set

{

_port = value;

}

}

private int mailCount = 0;

public int MailCount

{

get

{

return mailCount;

}

set

{

mailCount = value;

}

}

private int mailSpace = 0;

public int MailSpace

{

get

{

return mailSpace;

}

set

{

mailSpace = value;

}

}

private Socket socket = null;

public int port

{

get
{ return Port; }

}

//step 1: 连接一个POP3服务器,希望得到+OK的确认消息

public void Connect(string hostname)

{

//建立一个套接字

socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

IPHostEntry hostInfo = Dns.GetHostByName(hostname);

IPEndPoint endPoint = new IPEndPoint(hostInfo.AddressList[0], Port);

socket.Connect(endPoint);

string tmp = RecvLine(); //blocking,wait for '+OK'

Console.WriteLine(tmp);

}

//step 2:发送命令字USER和PASS

public void Login(string username,string password)

{

SendCommand("USER " + username);

string tmp=RecvLine();

Console.WriteLine("Server say: {0}", tmp);

SendCommand("PASS " + password);

string tmp1=RecvLine();

Console.WriteLine("Server say: {0}", tmp1);

}

//step 3:发送命令字STAT,请求服务器发回关于邮箱的统计资料,如邮件总数和总字节数

//C:STAT

//S:+OK nn mm

//nn是邮件数量,mm是大小

public void Stat()

{

SendCommand("STAT");

string tmp=RecvLine();

tmp = tmp.Substring(tmp.IndexOf(" ") + 1); //在+OK和一个空格之后得到邮件数量,字节数

string tmp1 = tmp.Substring(0, tmp.IndexOf(" ")).Trim();

MailCount=Int32.Parse(tmp.Substring(0, tmp.IndexOf(" ")).Trim());

Console.WriteLine("Server say: {0}", tmp);

// MailSpace = Int32.Parse(tmp1.Substring(0, tmp1.IndexOf(" ")).Trim());

}

// LIST [msg] ,msg参数是可选的,返回邮件数量和每个邮件的大小,如果没有msg参数,服务器将返回所有的邮件信息

// C:LIST

// S:+OK 187 9703827

//1 31502

//2 1168

//3 1826

//.
.

public void List()

{

SendCommand("LIST");

string tmp = RecvLine();

Console.WriteLine("Server say: {0}", tmp);

}

public void Dele(string mailNumber)

{

SendCommand("DELE " + mailNumber);

string tmp = RecvLine();

Console.WriteLine("Server say: {0}", tmp);

}

public void Quit()

{

SendCommand("QUIT");

string tmp = RecvLine();

Console.WriteLine("Server say: {0}", tmp);

}

//

//关闭打开的连接并且发送QUIT命令字,QUIT命令没有参数

public void Close()

{

if (socket == null)

return;

try

{

Quit(); //first invoke Quit method

}

finally

{

socket.Close();

}

}

private void SendCommand(string command)

{

command += " ";//必须在命令字后添加CRLF对

byte[] buffer = Encoding.ASCII.GetBytes(command.ToCharArray());

// 发送缓冲

int bytesSent = socket.Send(buffer, buffer.Length, 0);

if (bytesSent != buffer.Length)

throw new Exception("failed to send request to server");

}

// TODO :服务器以Multi-line应答

private string RecvMultiLine()

{

}

// 服务器以line+CRLF形式应答

private string RecvLine()

{

//需要添加一个空的终结符

byte[] buffer = new byte[bufsize + 1];

StringBuilder message = new StringBuilder(bufsize);

int bytesRead;

// 读取缓冲区

for (; ; )

{

bytesRead = socket.Receive(buffer, bufsize, SocketFlags.None);

//读取完毕

if (bytesRead == 0)

break;

buffer[bytesRead] = 0;

// conver char array to string

message.Append(Encoding.ASCII.GetChars(buffer, 0, bytesRead));

if (buffer[bytesRead - 1] == 10) //=LF #hex:0A #Dec:10

break;

}

string tmp = message.ToString();

if (tmp.StartsWith(OKFlag) == false) //服务器消息不是以+OK起始的确认消息

{

throw (new Exception(tmp));

}

return tmp;

}

}

}

上面的代码完成了监控的基本功能,但是还不够,首先缺少异常处理,比如在socket.connect() 那里,连接失败了怎么办?其次,如果你想把邮件收到本地,那么字符的编码就成了问题,尤其是汉字的处理比较麻烦,详细的情况可以查看 RFC822 .你可以完善基本的代码,实现本地POP3收信了.

现在可以测试一下:

Using directives#region Using directives

using System;

using System.Collections.Generic;

using System.Text;

#endregion

namespace Sky.MailMonitor

{

class Program

{

static void Main(string[] args)

{

Pop3 pop3 = new Pop3();

string username="xxxxxx";

string password="xxxxxx";

string hostname="pop3.163.com";

try

{

pop3.Connect(hostname);

pop3.Login(username, password);

pop3.Stat();

pop3.List();

}

catch(Exception e)

{

Console.WriteLine(e.Message);

}

finally

{

pop3.Close();

}

}

}

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有