转载

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

见图见图

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

……

二、折腾中

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

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

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

先看结果

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

再看看代码

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

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

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

一个是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 憋死我了………………

正文到此结束
Loading...