POP3(邮局协议3)是一种标准协议的最新版本接收电子邮件。POP3是一种客户机/服务器协议收到的电子邮件和为你了你的网络服务器。定期,你(或你的客户邮件收件人)检查你的信箱在服务器和下载任何邮件,可能使用POP3。传统的接收邮件方式使用的是未加密的接收方式,后期考虑到数据安全性能,传输过程中使用SSL加密.outlook 2007 以后的版本默认是加密的。
在90年代的DOS系统下,我们想访问一个文件夹,需要在控制台上输入一串命令,系统接收命令后开始工作。这个方式我称之为渐进式。Pop3的原理类似。
POP3的常用命令有:
USER 用户名
PASS 密码
STAT 返回信息数
RETR 读取邮件详情
QUIT 退出
首先我们定义公用的NetWorkStream,这个公共 流是我们获取邮件的关键。
调用接口公用方法:
private void WriteTo(ref NetworkStream netStream, string command) { string strToSend = command + "\r\n"; byte[] arrayToSend = System.Text.Encoding.ASCII.GetBytes(strToSend.ToCharArray()); if (netStream.CanWrite) netStream.Write(arrayToSend, 0, arrayToSend.Length); }
登陆PoP3时需要输入一个连接服务器的命令。
Client = new TcpClient(HostName, Port); Client.ReceiveTimeout = 2000; netStream = Client.GetStream(); streamReader = new StreamReader(Client.GetStream()); string strMessage = streamReader.ReadLine();
连接上POP3服务器上可以看到strMessage 成功返回了一个含有 +OK 的字符串,然后就可以输入用户名和密码了。
WriteTo(ref netStream, “USER **@qq.com”); WriteTo(ref netStream, “PASS ****”);
正常登陆返回未读邮件总数,接下来就可以读取每一封邮件了。
邮件的解析工作是一个很头疼的问题,因为所有的信息都包含在一个返回的流文件里面,看上去很没有条理。
文件流里包含一定格式的标志位,常用标志位有:
Subject 邮件主题
SendTime 发送时间
Content 内容
From 发件人
Attach 附件
解析邮件主题的公用方法
/// <summary> /// 查找完整数据索引号 /// </summary> /// <param name="context"></param> /// <param name="market"></param> /// <returns></returns> private int EndIndex(string context) { List<int> ints = new List<int>(); foreach (string item in mailMarkets) { int index = context.IndexOf(item, StringComparison.OrdinalIgnoreCase); if (index > 0) ints.Add(index); } var result = ints.OrderBy(p => p).ToList(); return result.Count > 0 ? result.First() : -1; }
解析邮件主题
int staIndex = strContent.IndexOf("Subject:"); prefixion = strContent.Remove(0, staIndex + 8); enIndex = EndIndex(prefixion); if (enIndex > 0) subject = prefixion.Substring(0, enIndex);
截取含有Subject的内容,去掉Subject后 便是邮件主题,然后主题转码。在主题正文中找出编码方式,如果是b,表示的是base64位。
for (int i = 0; i < arrs.Length; i++) { if (!string.IsNullOrEmpty(arrs[i])) { arrs[i] = arrs[i].Trim(); int n = arrs[i].Length; char first = arrs[i][0]; if (arrs[i][0] == '=') arrs[i] = arrs[i].Remove(0, 1); if (arrs[i].EndsWith("?= =")) arrs[i] = arrs[i].Replace("?= =", ""); if (arrs[i].EndsWith("?")) arrs[i] = arrs[i].Replace("?", ""); int lenght = arrs[i].Length; if (codeState.ToLower() == "b") Text += Encoding.GetEncoding(encoding).GetString(Convert.FromBase64String(arrs[i])) + " ";//"S09TRemrmOS4neWmjeeameS/nea5v+eyvuWNjua2sjE1bWw="));//Subject)); } }
接下来 取得邮件正文,正文内容含两种编码格式,BASE64位和Q位。常用的是BASE64. 解析时将字符转码
解析时Content 时 如果流文件含base64,即表示该正文是按base64转码的,我们解码就行。
Regex.Replace(strContent, "charset=.*Content-transfer-encoding.*", new MatchEvaluator(p => { if (p.Success) { var charsetPrefix = p.Value.Remove(0, p.Value.IndexOf("charset=") + 8); var charsetEncoding = string.Empty; if (charsetPrefix.StartsWith("GB2312", StringComparison.OrdinalIgnoreCase)) charsetEncoding = "GB2312"; else if (charsetPrefix.StartsWith("utf-8", StringComparison.OrdinalIgnoreCase)) charsetEncoding = "utf-8"; var transferContext = p.Value.Remove(0, p.Value.IndexOf("Content-transfer-encoding") + 26).Trim(); int transferEndIndex = EndIndex(transferContext); var transfered = transferContext; if (transferEndIndex > 0) { transfered = transferContext.Substring(0, transferEndIndex); } if (transfered.StartsWith("base64", StringComparison.OrdinalIgnoreCase)) { var baseStr = Regex.Split(transfered.Substring(6), "--"); //suLK1NK7z8I=--0__=C7BBF079DF9E146E8f9e8a93df938690918cC7BBF079DF9E146E foreach (var item in baseStr) { try { Context += Encoding.GetEncoding(charsetEncoding).GetString(Convert.FromBase64String(item)); } catch { continue; } } } } return null; }));