您的位置:首页 > 编程语言 > C#

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

2016-06-27 15:44 686 查看
转自http://www.cnblogs.com/PEPE/p/4632540.html?utm_source=tuicool&utm_medium=referral

一、故事
 
      首先通过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 憋死我了………………
 

作者:PEPE 

出处:http://pepe.cnblogs.com/ 

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: