C# MailMessage Attachment 中文名附件发邮件-Firefox中文显示正常,网页打开邮件附件中文名乱码

一、故事

首先通过CDO.Message来获取邮件EML相关数据:邮件标题、邮件内容、邮件附件、发件人、收件人、CC主要就这么几个,其次通过MailMessage来组织邮件通过Python来发送邮件!

就这么简简单单的需求!!问题出现了,中文附件名!Web打开始终是乱码!使用邮件客户端FireFox是OK的,查看了FireFox源码发现是乱码,这点说明FireFox的强大,非常强大!

Content-Type: application/octet-stream; name=鎶ラ攢鍗昪s.xlsx
Content-Transfer-Encoding: base64
Content-Disposition: attachment

见图见图

……

二、折腾中

出了问题想办法,一定要抱着始终相信一定可以解决的尤其是搞IT的一定有方法!大事化小,小事化无。先找卧底!第一个想到的便是CDO.Message那就从他下手。最后发现他是平民!

先说说走的路,干货的路,其他摸索的方法想了下数数应该有4,5种了:

读取EML转换成流,再获取附件再解码,发现中文名OK

先看结果

再看看代码

public class AttachmentExtractor
    {
        private static int imageCount;

        public static void Method(string path)
        {
            StreamReader reader = null;
            try
            {
                reader = new StreamReader(path);
                string line;
                StringBuilder sb = new StringBuilder();
                while ((line = reader.ReadLine()) != null)
                {
                    sb.Append(line.ToLower());
                    if (line.ToLower().StartsWith("content-disposition:attachment;") || line.ToLower().StartsWith("content-disposition: attachment;")) // found attachment
                    {
                        string fileName = GetAttachment(reader, line);
                        fileName = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(fileName.Replace("=?utf-8?B?", "").Replace("?=", "")));
                    }
                    if (line.ToLower().StartsWith("content-type:image/")) // found embedded image
                    {
                        ExtractContent(reader, GetImage(reader, line));
                    }
                }
            }
            catch (IOException)
            {
                Console.WriteLine("找不到文件!");
            }
            finally
            {
                if (reader != null) reader.Close();
            }

        }

        private static string GetAttachment(TextReader reader, string line)
        {
            if (!line.Contains("filename"))
            {
                line = reader.ReadLine(); // Thunderbird: filename start at
                //second line
            }
            return GetFilenameNew(reader, line);
        }

        private static string GetImage(TextReader reader, string line)
        {
            if (!line.Contains("name"))
            {
                line = reader.ReadLine(); // Thunderbird: filename start at
                //second line
            }
            if (!line.Contains("name")) // embedded image does not have name
            {
                AdvanceToEmptyLine(reader);

                return "image" + imageCount++ + ".jpg"; // default to jpeg
            }

            return GetFilename(reader, line);
        }

        private static string GetFilename(TextReader reader, string line)
        {
            string filename;
            int filenameStart = line.IndexOf(‘"‘) + 1;

            if (filenameStart > 0)
            {
                filename = line.Substring(filenameStart, line.Length -
                filenameStart - 1);
            }
            else // filename does not have quote
            {
                filenameStart = line.IndexOf(‘=‘) + 1;
                filename = line.Substring(filenameStart, line.Length -
                filenameStart);
            }

            AdvanceToEmptyLine(reader);

            return filename;
        }

        private static string GetFilenameNew(TextReader reader, string line)
        {
            string filename;
            int filenameStart = line.IndexOf(‘"‘) + 1;

            if (filenameStart > 0)
            {
                filename = line.Substring(filenameStart, line.Length -
                filenameStart - 1);
            }
            else // filename does not have quote
            {
                filenameStart = line.IndexOf(‘=‘) + 1;
                filename = line.Substring(filenameStart, line.Length -
                filenameStart);
            } 

            return filename;
        }

        private static void AdvanceToEmptyLine(TextReader reader)
        {
            string line;

            while ((line = reader.ReadLine()) != null)
            {
                if (String.IsNullOrEmpty(line)) break;
            }
        }

        private static void ExtractContent(TextReader reader, string filename)
        {
            string line;
            var content = new StringBuilder();

            while ((line = reader.ReadLine()) != null)
            {
                if (String.IsNullOrEmpty(line)) break;

                content.Append(line);
            }

            if (content.Length > 0)
            {
                byte[] buffer = Convert.FromBase64String(content.ToString());
                #region 7.7
                if (!File.Exists(filename))
                {
                    return;
                }
                #endregion
                using (Stream writer = new FileStream(filename,
                FileMode.Create))
                {
                    writer.Write(buffer, 0, buffer.Length);
                }
            }
        }
    }
public RedEmail()
        {
            InitializeComponent();
            this.txtEmailPath.Text = "C:\\Users\\Administrator\\Desktop\\4a3266e6-23bd-11e5-9703-0050569a7cc2.eml";

            AttachmentExtractor.Method(txtEmailPath.Text);
        }

仔细看完代码会发现获取的附件名是编码过的,需要截取。这个要注意!发现经常不写写,不说说都不知道如何表达我那被困的感受!!!不过!有结果就是胜利!如下:

可喜的是,我找到了原因:CDO.Message不是卧底!是个良民!!!他只是一个善良的二道贩子!

三、看到曙光

好了,总共就两人,一个平民了,那么另一个一定是卧底咯-MailMessage

先看胜利的结果,这个喜悦之情那!!

一个是EML里面的附件-乱码,一个是通过改良后代码上传上去的-OK……(ps 写博客都不忘给我老婆店铺做广告,主要是因为我们博客园老牛B了,经常会被其他网站转载,又不写转载信息!)

搞IT的代码最直接看看代码,如下:

                //MemoryStream ms =
                //    new MemoryStream(File.ReadAllBytes(@"C:\\Users\\Administrator\\Desktop\\RDP_需求规格说明书.docx"));
                ////message.Attachments.Add(new System.Net.Mail.Attachment(ms, "RDP_需求规格说明书.docx"));

                //System.Net.Mime.ContentType ct = new System.Net.Mime.ContentType(System.Net.Mime.MediaTypeNames.Text.Plain);
                //System.Net.Mail.Attachment attach = new System.Net.Mail.Attachment(ms, ct);
                //attach.ContentDisposition.FileName = "产品经理2.docx";

                //attach.NameEncoding = Encoding.GetEncoding("utf-8");
                //      `message.Attachments.Add(attach);

                System.Net.Mail.Attachment attachment = AttachmentHelper.CreateAttachment(@"C:\\Users\\Administrator\\Desktop\\产品经理2.jpg", "产品经理2.jpg", TransferEncoding.Base64);

                message.Attachments.Add(attachment);
                //var attachment = new Attachment(new MemoryStream(File.ReadAllBytes(@"C:\\Users\\Administrator\\Desktop\\产品经理2.jpg")), new System.Net.Mime.ContentType("application/vnd.ms-excel"));
                ////bool flag = File.Exists(@"C:\\Users\\Administrator\\Desktop\\产品经理2.jpg");
                //FileStream fs = new FileStream(@"C:\\Users\\Administrator\\Desktop\\产品经理2.jpg", FileMode.Open, FileAccess.Read);
                //System.Net.Mime.ContentType ct = new System.Net.Mime.ContentType(System.Net.Mime.MediaTypeNames.Text.Plain);
                //System.Net.Mail.Attachment attach = new System.Net.Mail.Attachment(fs, ct);
                //attach.ContentDisposition.FileName =  "产品经理2.jpg";
                //fs.Close();
                //message.Attachments.Add(attach);   

看到了么!注释的就是实验的!我说我是折腾了半天解决的!

好了,揭开神秘的面纱AttachmentHelper  

 public class AttachmentHelper
    {
        public static System.Net.Mail.Attachment CreateAttachment(string attachmentFile, string displayName, TransferEncoding transferEncoding)
        {
            System.Net.Mail.Attachment attachment = new System.Net.Mail.Attachment(attachmentFile);
            attachment.TransferEncoding = transferEncoding;

            string tranferEncodingMarker = String.Empty;
            string encodingMarker = String.Empty;
            int maxChunkLength = 0;

            switch (transferEncoding)
            {
                case TransferEncoding.Base64:
                    tranferEncodingMarker = "B";
                    encodingMarker = "UTF-8";
                    maxChunkLength = 30;
                    break;
                case TransferEncoding.QuotedPrintable:
                    tranferEncodingMarker = "Q";
                    encodingMarker = "ISO-8859-1";
                    maxChunkLength = 76;
                    break;
                default:
                    throw (new ArgumentException(String.Format("The specified TransferEncoding is not supported: {0}", transferEncoding, "transferEncoding")));
            }

            attachment.NameEncoding = Encoding.GetEncoding(encodingMarker);

            string encodingtoken = String.Format("=?{0}?{1}?", encodingMarker, tranferEncodingMarker);
            string softbreak = "?=";
            string encodedAttachmentName = encodingtoken;

            if (attachment.TransferEncoding == TransferEncoding.QuotedPrintable)
                encodedAttachmentName = HttpUtility.UrlEncode(displayName, Encoding.Default).Replace("+", " ").Replace("%", "=");
            else
                encodedAttachmentName = System.Convert.ToBase64String(Encoding.UTF8.GetBytes(displayName));

            encodedAttachmentName = SplitEncodedAttachmentName(encodingtoken, softbreak, maxChunkLength, encodedAttachmentName);
            attachment.Name = encodedAttachmentName;

            return attachment;
        }

        private static string SplitEncodedAttachmentName(string encodingtoken, string softbreak, int maxChunkLength, string encoded)
        {
            int splitLength = maxChunkLength - encodingtoken.Length - (softbreak.Length * 2);
            var parts = SplitByLength(encoded, splitLength);

            string encodedAttachmentName = encodingtoken;

            foreach (var part in parts)
                encodedAttachmentName += part + softbreak + encodingtoken;

            encodedAttachmentName = encodedAttachmentName.Remove(encodedAttachmentName.Length - encodingtoken.Length, encodingtoken.Length);
            return encodedAttachmentName;
        }

        private static IEnumerable<string> SplitByLength(string stringToSplit, int length)
        {
            while (stringToSplit.Length > length)
            {
                yield return stringToSplit.Substring(0, length);
                stringToSplit = stringToSplit.Substring(length);
            }

            if (stringToSplit.Length > 0) yield return stringToSplit;
        }
    }

这个牛B的类不是我写的!声明下!我可没那么牛×,是哥千辛万苦+输入了英文才找到的!更坚定了我要学好英文的夙愿!!!!

四、后话

好了,可以安心改改代码,发布一个Demo了。

总结下:

1、要有不放弃不抛弃。

2、要敢自我调侃的娱乐精神。

3、关键时刻别忘了Google,国外的月亮有时候真的比国内圆!

一口气,好了,我去WC 憋死我了………………

时间: 2024-11-08 23:24:57

C# MailMessage Attachment 中文名附件发邮件-Firefox中文显示正常,网页打开邮件附件中文名乱码的相关文章

Exchange 2016发送给内部中继服务器邮件后收件人显示winmail.dat

1.前戏          最近遇到一个问题,Exchange邮箱发送一个带附件的邮件给内部的另外一个非Exchange邮件系统邮箱的用户邮件,收件人收到邮件后不使用Outlook客户端打开邮件时显示为winmail.dat:如果收件人使用Outlook打开则可以正常查看邮件附件. 2.了解这个问题之前我先介绍一下环境情况 现场环境为WIndows Server 2012 R2+Exchange 2016.AD的域名为contoso.local,Exchange的接收域为:contoso.loc

C#操作EML邮件文件实例(含HTML格式化邮件正文和附件)

使用QQ邮箱.163邮箱等导出的EML邮件,包含了邮件的发件人.主题.内容.附件等所有信息,该实例就如何解析这些信息,并在编辑后保存做个Demo. 如下图所示,EML文件是编码后的文本文件,可以使用正则表达式识别其中的关键字,例如Received.Sender.Cc.Bcc.From等. 但解析后的内容是经过编码后的,例如Sender的内容X-QQ-FEAT……,这个时候需要对内容进行解码,一般使用Base64进行编码. EML源文件包含了很多信息,除了使用邮箱客户端看到的收件人.发件人.主题.

.NET开发邮件发送功能的全面教程(含邮件组件源码)

ref: http://www.cnblogs.com/heyuquan/p/net-batch-mail-send-async.html 今天,给大家分享的是如何在.NET平台中开发"邮件发送"功能.在网上搜的到的各种资料一般都介绍的比较简单,那今天我想比较细的整理介绍下: 1)         邮件基础理论知识 2)         邮件发送相关.NET类库 3)         介绍我开发的一个发送邮件的小组件(MailHelper) 4)         MailHelper组

读取XML 发送网页版邮件

DataSet ds = new DataSet(); ds.ReadXml(AppDomain.CurrentDomain.BaseDirectory + "XML\\Mail.xml"); if (ds.Tables.Count > 0) { DataTable dt = ds.Tables[0]; if (dt.Rows.Count > 0) { body = dt.Rows[0]["content"].ToString(); } } body =

C#邮件接收系统核心代码(接收POP3邮件IMAP邮件)

/* * Created by SharpDevelop. * User: Administrator * Date: 2013/11/18 * Time: 20:55 * * To change this template use Tools | Options | Coding | Edit Standard Headers. */ using System; using System.Linq; using System.IO; using System.Collections.Gener

邮件营销撩妹利器:个性化邮件

这阵子火热得令万千少女.少妇,乃至大妈神魂颠倒.哭着喊着要嫁的仲基欧巴,其撩妹技能三千二百式,招招令人腿软. 今天,Focussend就来和大家聊聊这个撩妹技巧-- 额咳咳,是邮件营销市场的撩妹技巧. 我们的客户, 就好比现在外头春末夏初露着白花花大腿的妹子们.为了尽快抱得妹子归,就要了解妹子的习惯,喜好,针对性互动,才能抓住妹子们的心-- 咳咳咳(最近嗓子不舒服),是抓住客户的心. 下面隆重介绍<FS Book>撩妹三十六招: 第一招:靠近靠近,死皮赖脸地靠近! 第一式:宣告存在 如果你没有

IMAP(Internet Mail Access Protocol,Internet邮件访问协议)以前称作交互邮件访问协议(Interactive Mail Access Protocol)。

IMAP(Internet Mail Access Protocol,Internet邮件访问协议)以前称作交互邮件访问协议(Interactive Mail Access Protocol).IMAP是斯坦福大学在1986年开发的一种邮件获取协议.它的主要作用是邮件客户端(例如MS Outlook Express)可以通过这种协议从邮件服务器上获取邮件的信息,下载邮件等.当前的权威定义是RFC3501.IMAP协议运行在TCP/IP协议之上,使用的端口是143.它与POP3协议的主要区别是用户

混合部署环境本地邮件被云端传输规则当成外部邮件处理

最近,我们遇到一个Hybrid环境中,来自本地的邮件被云端传输规则当作外部邮件处理的问题,下面将分析过程分享给大家. 环境:本地Exchange Server 2013:Exchange Online E3问题:管理员在Exchange Online中创建了一条传输规则,在来自组织外的邮件上都添加一条免责声明,如下图: 之后,有云端用户报告,收到本地用户发来的邮件,也被应用了这条规则.接到这个问题后,我们先从Exchange Online的EAC界面查看了云端的接受域,确认本地域被列为权威域:

bootstrap Glyphicon字体在firefox不显示【CORS问题】

最近使用bootstrap来试水一个手机版网站的项目,在用到里面的Glyphicon字体的时候,那些glyphicon-search 类套用上去之后无法在firefox上显示,显示为乱码,IE,Safari,chrome等等显示正常. 奇怪,一直刷新跟清缓存都无法解决这个问题.后来在firefox的控制面板上看到以下的信息 网上能看到有类似的同行也有这个经历 http://www.yanxiaoyu.com/show-23-19-1.html 在网上搜到上面的解决方法 http://enable