给梦一个奔跑的方向!
PDF Print E-mail
User Rating: / 0
PoorBest 
Written by xlingfairy
Thursday, 09 July 2009 10:58
 
POP3命令码如下: 
命令 参数 状态 描述 
------------------------------------------ 
USER username 认可 此命令与下面的pass命令若成功,将导致状态转换 
PASS password 认可 
APOP Name,Digest 认可 Digest是MD5消息摘要 
------------------------------------------ 
STAT None 处理 请求服务器发回关于邮箱的统计资料,如邮件总数和总字节数 
UIDL [Msg#] 处理 返回邮件的唯一标识符,POP3会话的每个标识符都将是唯一的 
LIST [Msg#] 处理 返回邮件数量和每个邮件的大小 
RETR [Msg#] 处理 返回由参数标识的邮件的全部文本 
DELE [Msg#] 处理 服务器将由参数标识的邮件标记为删除,由quit命令执行 
RSET None 处理 服务器将重置所有标记为删除的邮件,用于撤消DELE命令 
TOP [Msg#] 处理 服务器将返回由参数标识的邮件前n行内容,n必须是正整数 
NOOP None 处理 服务器返回一个肯定的响应
 
如果POP3服务器是SSL的(比如GMAIL),连接服务器需要用 SslStream.
 
                TcpClient tc = new TcpClient(server, port);
                if (tc == null) {
                    NotifyMessageFun("错误", "尝试连接服务器" + server + ":" + port + "失败", NotifyMsgType.Error);
                    throw new Exception("连接服务器失败");
                }
 
                Stream st;
                if (isSSL) {
                    SslStream sst = new SslStream(tc.GetStream());
                    sst.AuthenticateAsClient(server);
                    st = sst;
                } else {
                    NetworkStream nst = tc.GetStream();
                    st = nst;
                }
 
                sw = new StreamWriter(st);
                sr = new StreamReader(st);
 
连接之后,一定要先读一行,这一行是POP3服务器返回的欢迎信息,如果不读这一行,接着使用的USER 命令后在读,返回的还是这条欢迎信息,验证用户名是否正确的那条返回信息是在下一行才被返回,这样就影响了判断用户名是否正确。
 
如果提供的信息是正确的,返回的着3个字符是:+OK,否则是-ERR ,可以用这个来判断提供的信息是否正确,
 
LIST , RETR , UIDL, TOP 这几条命令返回的是多行,最后一行是一个英文的句号:“.”
 
UIDL返回的是邮件标识,格式如下:
 
+OK
1 GmailId11f312dd5ad8c1ad
2 GmailId11f312ee21e33479
3 GmailId11f36549f7112ade
.
 
GMAIL返回的顺序是最新的在最下面,其它的POP3服务器我没测,不知道是什么顺序。不过,同一台POP3服务器,返回的UIDL顺序一定是一致的。所以,只需要把UIDL存起来,下次在取出UIDL结果后,和以存的UIDL结果对比一下,就知道哪条是新邮件的标识了。
 
 

获取邮件头

 
不知道是不是所有POP3服务器 TOP 命令返回的信息顺序是不是一至,所以,只有约摸着取了。GMAIL的TOP 30 返回的信息足够取得邮件头的信息了。不过,不敢保存哪一行存的是 Subject, 哪一行存的是 Date 和  From ,所以,只有循环来判断。
Subject: 开头的就是标题,From开头的是发件人。
 
另外,如果包含中文,一般都会被加B编码或Q编码,不解码的话,你是看不懂什么意思的。
 
 
B编码是指 Base64, Q编码是指Quote_Printable
 
B编码是类似这样的:
Subject:   =?gb2312?B?yq7Su8qx?=
 
Q编码是这个样子: =B3=C2=BF=A1=C7=E5=A3=AC=C4=FA=BA=C3=A3=A1
 
Quoted-Printable   加码规则(RFC   1341):   
 
  1.   字符用   =XX   形式表示,其中   XX   是该字符的十六进制值,   
  必须为   0-9   或者   A-F   (使用大写字符),除非有可替换说明,   
  否则,此原则是强制性的。   
    
  2.   其中,十进制值   33-60   &   62-126(注意:   即不包含   '='   )     
  可以作为标准   ASCII   从而不进行转换。   
    
  3.   另外,十进制值   9-32   也可以作为制表和格式控制字符,   
  从而不进行转换。(注意,这个不是必须执行的,即也可以转换)   
    
  4.   由于在   RFC822   协议中规定主体   body   文本中各行均有最大字   
  符限制,因此,当主体文本中出现   CRLF   或者   LFCR   字符序列,   
  或者单独的   CR   以及   LF   字符的时候,必须转换成对应的     
  "=0D=0A","=0A=0D","=0D","=0A"   等编码来表示。   
    
  5.   (关于软回车的问题)   Quoted-Printable   编码要求编码后每行   
  最大字符数量不得超过   76   个字符。如果对大于该字符数量的行进   
  行编码,则必须使用软回车。所以,对于某个以编码行的最后加上   
  '='符号,则表示最后这个   '='   是一个无意义的软回车。所以,如   
  果一个尚未编码的行的内容如下的话:  
 
这里我用一个正则表达来取出编码(encoding)和编码方式(codeType),及需要取出的主体(ctx, ctx2):
private readonly Regex codingReg = new Regex(@"=\?(?<encoding>.*?)\?(?<codeType>.*?)\?(?<ctx>.*?)\?=(?<ctx2>.*)",RegexOptions.Compiled | RegexOptions.IgnoreCase);
 
        /*
         * =?gb2312?B?"或者"=?gb2312?Q?"或者没有
        */
        private string parseString(string str){
            Match ma = codingReg.Match(str);
            if (ma.Success) {
                string encoding = ma.Groups["encoding"].Value;
                string codeType = ma.Groups["codeType"].Value;
                string ctx = ma.Groups["ctx"].Value;
                string ctx2 = ma.Groups["ctx2"].Value;
 
                if (codeType == "B")
                    ctx = Encoding.GetEncoding(encoding).GetString(Convert.FromBase64String(ctx));
                else if (codeType == "Q")
                    ctx = DecodeQ(ctx);
 
                return ctx + " " + ctx2;
            }
            return str;
        }
 
        private string DecodeQ(string str) {
            //string[] tmp = str.Split('=');
            string[] tmp = str.Split(new char[] { '=' }, StringSplitOptions.RemoveEmptyEntries);
            byte[] bt = new byte[tmp.Length];
 
            for (int i = 0; i < tmp.Length; i++) {
                bt[i] = (byte)int.Parse(tmp[i], System.Globalization.NumberStyles.HexNumber);
            }
 
            return Encoding.Default.GetString(bt);
        }
 
B编码的,我测试过,没问题,但是Q编码的,我还没遇到,没测试,不过,DecodeQ是通过的。
 
Last Updated ( Thursday, 09 July 2009 11:12 )
 

Add comment


Security code
Refresh

Popular Contents

Recommend

Site Info

Members : 1
Content : 130
Web Links : 7
Content View Hits : 99635

Links