最近在使用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();//手动高亮
}