zoukankan      html  css  js  c++  java
  • c# 使用NetStream接收 解析邮件

    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;
                        }));
  • 相关阅读:
    亲历dataguard的一些经验问答题
    [转]ORA-38500: USING CURRENT LOGFILE option not available without stand
    修改npm全局安装模式的路径
    Vue 环境搭建
    Linux下查看系统版本号信息的方法
    每天一个Linux命令(12):su命令
    Ubuntu 首次给root用户设置密码
    适用于Linux的windows子系统
    IDEA的terminal设置成Linux的终端一样
    Windows模拟linux终端工具Cmder+Gow
  • 原文地址:https://www.cnblogs.com/yzp12sina/p/3503278.html
Copyright © 2011-2022 走看看