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

推荐订阅源

W
WeLiveSecurity
T
The Exploit Database - CXSecurity.com
C
CXSECURITY Database RSS Feed - CXSecurity.com
S
Security @ Cisco Blogs
T
Threat Research - Cisco Blogs
TaoSecurity Blog
TaoSecurity Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
腾讯CDC
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
T
The Blog of Author Tim Ferriss
Microsoft Azure Blog
Microsoft Azure Blog
罗磊的独立博客
F
Full Disclosure
博客园 - 【当耐特】
C
CERT Recently Published Vulnerability Notes
Engineering at Meta
Engineering at Meta
Application and Cybersecurity Blog
Application and Cybersecurity Blog
T
Threatpost
I
Intezer
V2EX - 技术
V2EX - 技术
H
Hackread – Cybersecurity News, Data Breaches, AI and More
The Hacker News
The Hacker News
小众软件
小众软件
Google DeepMind News
Google DeepMind News
T
Tailwind CSS Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
B
Blog RSS Feed
Microsoft Security Blog
Microsoft Security Blog
N
News | PayPal Newsroom
MyScale Blog
MyScale Blog
AI
AI
Vercel News
Vercel News
Spread Privacy
Spread Privacy
美团技术团队
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
The GitHub Blog
The GitHub Blog
V
Vulnerabilities – Threatpost
Schneier on Security
Schneier on Security
Cyberwarzone
Cyberwarzone
G
GRAHAM CLULEY
Help Net Security
Help Net Security
Hacker News: Ask HN
Hacker News: Ask HN
Google DeepMind News
Google DeepMind News
MongoDB | Blog
MongoDB | Blog
L
LINUX DO - 热门话题
U
Unit 42
L
LangChain Blog
Recent Announcements
Recent Announcements

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