最近在使用MailKit組件發送郵件,看了一些博客其實還是蠻簡單的,但是發送附件的時候卻產生了不小的問題,附件的中文名字是亂碼的,或者附件的名字過長就會無效,附件的名字在QQ郵箱中會變成類似
tcmime.1046.1479.1696.bin
這樣問文件名而在163郵箱中則可能變成類似
ATT00002.docx
的名稱。如果你也遇到了這樣的問題,那么我想你一定很期待接下來的解決辦法。
解決文件名不能使用中文
原因是字符編碼的問題
MimePart attachment = null;
var fs = new FileStream(path, FileMode.Open);
list.Add(fs);
attachment = new MimePart(contentType)
{
Content = new MimeContent(fs),
ContentDisposition = new ContentDisposition(ContentDisposition.Attachment),
ContentTransferEncoding = ContentEncoding.Base64,
};
var charset = "GB18030";
attachment.ContentType.Parameters.Add(charset, "name", fileName);
attachment.ContentDisposition.Parameters.Add(charset, "filename", fileName);
解決附件名字中文亂碼主要依靠最后三行代碼,將name和filename的字符集指定為GB18030即可。
解決文件名不能超過41字符
為什么會不超過41個字符呢?
引用github上MailKit的issue
大意是 你使用的mail client 不支持 rfc2231 編碼,最有可能的是,它期望的文件名參數編碼使用rfc2047編碼(理論上從來沒有人使用rfc2047編碼參數值...,但是,哎... 有些郵件客戶端就是 sucks)
然后這個回答者給出了兩種解決方案,我使用了第一種如下:
var attachment = bodyBuilder.Attachments.Add (.....);
foreach (var param in attachment.ContentDisposition.Parameters)
param.EncodingMethod = ParameterEncodingMethod.Rfc2047;
foreach (var param in attachment.ContentType.Parameters)
param.EncodingMethod = ParameterEncodingMethod.Rfc2047;
第二種你可以點issue查看,完整的代碼看最后
別忘了釋放附件
By the way , 我還遇到了一個問題就是附件在發送之后附件使用的文件流沒有被釋放掉,我覺得這是個bug應該會在以后更正,不過現在你可以在添加附件是將文件流的引用收集起來,等到郵件發送之后釋放掉:
List<FileStream> list = new List<FileStream>(attachments.Count());
foreach (var path in attachments)
{
if (!File.Exists(path))
{
throw new FileNotFoundException("文件未找到", path);
}
var fileName = Path.GetFileName(path);
var fileType = MimeTypes.GetMimeType(path);
var contentTypeArr = fileType.Split('/');
var contentType = new ContentType(contentTypeArr[0], contentTypeArr[1]);
MimePart attachment = null;
var fs = new FileStream(path, FileMode.Open);
list.Add(fs);
attachment = new MimePart(contentType)
{
Content = new MimeContent(fs),
ContentDisposition = new ContentDisposition(ContentDisposition.Attachment),
ContentTransferEncoding = ContentEncoding.Base64,
};
var charset = "GB18030";
attachment.ContentType.Parameters.Add(charset, "name", fileName);
attachment.ContentDisposition.Parameters.Add(charset, "filename", fileName);
foreach (var param in attachment.ContentDisposition.Parameters)
param.EncodingMethod = ParameterEncodingMethod.Rfc2047;
foreach (var param in attachment.ContentType.Parameters)
param.EncodingMethod = ParameterEncodingMethod.Rfc2047;
collection.Add(attachment);
}
await SendEmail(body, subject, isHtml, to, cc, collection);
foreach (var fs in list)
{
fs.Dispose();//手動高亮
}