惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
腾讯CDC
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
L
LINUX DO - 热门话题
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Project Zero
Project Zero
V
Vulnerabilities – Threatpost
Cisco Talos Blog
Cisco Talos Blog
P
Palo Alto Networks Blog
C
Cisco Blogs
A
Arctic Wolf
月光博客
月光博客
The GitHub Blog
The GitHub Blog
T
The Blog of Author Tim Ferriss
量子位
小众软件
小众软件
Latest news
Latest news
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Microsoft Security Blog
Microsoft Security Blog
T
The Exploit Database - CXSecurity.com
Security Latest
Security Latest
N
Netflix TechBlog - Medium
K
Kaspersky official blog
人人都是产品经理
人人都是产品经理
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
博客园_首页
Y
Y Combinator Blog
P
Proofpoint News Feed
H
Hackread – Cybersecurity News, Data Breaches, AI and More
M
MIT News - Artificial intelligence
T
Threat Research - Cisco Blogs
S
Schneier on Security
D
Docker
Scott Helme
Scott Helme
MyScale Blog
MyScale Blog
Spread Privacy
Spread Privacy
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
GbyAI
GbyAI
有赞技术团队
有赞技术团队
Google DeepMind News
Google DeepMind News
The Hacker News
The Hacker News
H
Help Net Security
Simon Willison's Weblog
Simon Willison's Weblog
J
Java Code Geeks
C
Cyber Attacks, Cyber Crime and Cyber Security
T
Tenable Blog
B
Blog
Know Your Adversary
Know Your Adversary
IT之家
IT之家

博客园 - xpoint

Sybase 11.0.3 bcp数据报错! Sybase SQL Server 11.0.x 调优方案...(未完成) Windows Server Family 上安装Office 2000 你在使用Gmail,Wallop,MSN Spaces,Three Degrees吗? 网易的邮箱太慢了,还要别的选择吗? 学了学awk,也算是收获 Microsoft PowerToys for Windows XP 给Windows,SCO,AIX添加静态路由 给博客园的bloger提供若干GMail邀请。(暂放半天,明天移帖) 微软的应用程序块列表 反射的任务 微软为什么把标准提升的这么快, .Net Framework 1.1-> 2.0,连核心的类库都换了! 让你的gVim支持Miscrosoft Visual C++ 2003 设置一个Label控件上文字的字体样式和字体大小随机的代码 得到本机socket选项的全部默认值。 Linux TCP/IP 协议栈源码分析(一) 国外高手参加世界编程大赛时的参赛作品(转载) UltraEdit-32中的小bug。 还是关于《设计模式》
了解POP3协议,使用简单的代码监控pop3邮箱,或者不用代码,直接使用telnet
xpoint · 2004-08-04 · via 博客园 - xpoint

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收信了.
现在可以测试一下: