C# 如何使用Mailkit下载电子邮件附件
我正在使用中的代码使用MailKit从邮件下载附件。在检索附件的foreach循环中,它总是返回空。因为它是空的,所以不进入foreach循环。如果我做错了什么,请纠正我C# 如何使用Mailkit下载电子邮件附件,c#,asp.net,imap,mime,mailkit,C#,Asp.net,Imap,Mime,Mailkit,我正在使用中的代码使用MailKit从邮件下载附件。在检索附件的foreach循环中,它总是返回空。因为它是空的,所以不进入foreach循环。如果我做错了什么,请纠正我 var messages = client.Inbox.Fetch(0, -1, MessageSummaryItems.Full | MessageSummaryItems.UniqueId); int unnamed = 0; foreach (var message in
var messages = client.Inbox.Fetch(0, -1, MessageSummaryItems.Full | MessageSummaryItems.UniqueId);
int unnamed = 0;
foreach (var message in messages)
{
var multipart = message.Body as BodyPartMultipart;
var basic = message.Body as BodyPartBasic;
if (multipart != null)
{
//Here the attachments is always empty even though my mail has email with attachements
var attachments = multipart.BodyParts.OfType<BodyPartBasic>().Where(x => x.IsAttachment);
foreach (var attachment in attachments)
{
var mime = (MimePart)client.Inbox.GetBodyPart(message.UniqueId.Value, attachment);
var fileName = mime.FileName;
if (string.IsNullOrEmpty(fileName))
fileName = string.Format("unnamed-{0}", ++unnamed);
using (var stream = File.Create(fileName))
mime.ContentObject.DecodeTo(stream);
}
}
else if (basic != null && basic.IsAttachment)
{
var mime = (MimePart)client.Inbox.GetBodyPart(message.UniqueId.Value, basic);
var fileName = mime.FileName;
if (string.IsNullOrEmpty(fileName))
fileName = string.Format("unnamed-{0}", ++unnamed);
using (var stream = File.Create(fileName))
mime.ContentObject.DecodeTo(stream);
}
}
var messages=client.Inbox.Fetch(0,-1,MessageSummaryItems.Full | MessageSummaryItems.UniqueId);
int unnamed=0;
foreach(消息中的var消息)
{
var multipart=message.Body作为BodyPartMultipart;
var basic=消息体作为BodyPartBasic;
如果(多部分!=null)
{
//这里的附件总是空的,即使我的邮件中有带有附件的电子邮件
var attachments=multipart.BodyParts.OfType(),其中(x=>x.IsAttachment);
foreach(附件中的var附件)
{
var mime=(MimePart)client.Inbox.GetBodyPart(message.UniqueId.Value,附件);
var fileName=mime.fileName;
if(string.IsNullOrEmpty(文件名))
fileName=string.Format(“未命名-{0}”,++未命名);
使用(var stream=File.Create(文件名))
mime.ContentObject.DecodeTo(流);
}
}
else if(basic!=null&&basic.IsAttachment)
{
var mime=(MimePart)client.Inbox.GetBodyPart(message.UniqueId.Value,basic);
var fileName=mime.fileName;
if(string.IsNullOrEmpty(文件名))
fileName=string.Format(“未命名-{0}”,++未命名);
使用(var stream=File.Create(文件名))
mime.ContentObject.DecodeTo(流);
}
}
首先要注意的是MIME是一个树结构,而不是一个平面列表。BodyPartMultipart可以包含其他BodyPartMultipart子项以及BodyPartBasic子项,因此当您遇到另一个BodyPartMultipart时,您也需要深入到该子项中
我的猜测是,您正在检查的消息具有嵌套的多部分,这就是您遇到问题的原因
或者“附件”没有一个值为“附件”的内容处理头。下面是我用来遍历MIME树结构以获取所有可能的附件的方法。请注意,至少在我测试的电子邮件中,
IsAttachment
标志从未设置为true
首先,创建一个递归函数,以IEnumerable
的形式检索所有基本正文部分(包含消息实际内容的MIME消息部分):
私有静态IEnumerable GetBasicBodyParts(此BodyPart)
{
var multipart=零件作为BodyPartMultipart;
var basic=零件作为BodyPartBasic;
如果(多部分!=null)
{
foreach(多部分车身部件中的var子部分)
{
如果(子部分为BodyPartBasic)
{
将返回子部分作为BodyPartBasic;
}
其他的
{
foreach(子部分GetBasicBodyParts()中的var子部分)
{
收益子部分;
}
}
}
}else if(基本!=null)
{
基本收益率;
}
其他的
{
屈服断裂;
}
}
然后将该函数放在“下载”函数中使用,该函数与@jstedfast在其他帖子中提供的非常类似:
public static IEnumerable<FileInfo> DownloadAttachments(this EmailClient client, IMessageSummary message,
string destination)
{
fileNameFilter = fileNameFilter ?? AlwaysTrue;
if (!Directory.Exists(destination))
Directory.CreateDirectory(destination);
var folder = client.Inbox;
folder.Open(FolderAccess.ReadOnly);
foreach (var part in message.Body.GetBasicBodyParts())
{
var mimeHeader = (MimePart) folder.GetBodyPart(message.UniqueId.Value, part, headersOnly: true);
var headerFileName = mimeHeader.FileName;
if (string.IsNullOrWhiteSpace(headerFileName))
continue;
var mime = (MimePart) folder.GetBodyPart(message.UniqueId.Value, part);
var fileName = mime.FileName;
var filePath = Path.Combine(destination, fileName);
using (var stream = File.Create(filePath))
mime.ContentObject.DecodeTo(stream);
yield return new FileInfo(filePath);
}
}
公共静态IEnumerable DownloadAttachments(此EmailClient客户端、IMessageSummary邮件、,
字符串目的地)
{
fileNameFilter=fileNameFilter±AlwaysTrue;
如果(!Directory.Exists(destination))
CreateDirectory(目的地);
var folder=client.Inbox;
folder.Open(FolderAccess.ReadOnly);
foreach(message.Body.GetBasicBodyParts()中的var部分)
{
var mimeHeader=(MimePart)folder.GetBodyPart(message.UniqueId.Value,part,headersOnly:true);
var headerFileName=mimeHeader.FileName;
if(string.IsNullOrWhiteSpace(headerFileName))
继续;
var mime=(MimePart)folder.GetBodyPart(message.UniqueId.Value,part);
var fileName=mime.fileName;
var filePath=Path.Combine(目标,文件名);
使用(var stream=File.Create(filePath))
mime.ContentObject.DecodeTo(流);
返回新的FileInfo(filePath);
}
}
请注意,此功能:
- 跳过没有文件名的文件。如果要保留这些文件,可以从@jstedfast的其他示例中添加
计数器。您还可以添加其他逻辑,根据文件名或MIME头中的其他信息筛选出文件unnamed
- 首先只下载附件的标题。这允许文件名过滤,而无需先下载内容
- 是一种扩展方法,因此可以像这样使用:
client.DownloadAttachments(someMessage,@“C:\tmp\attachments”)
- 为保存的每个附件返回
对象。这对我很有用,但可能与其他人无关。这不是绝对必要的System.IO.FileInfo
我希望这对其他人有所帮助。您能提供任何示例或解决方法,以便通过上述过程下载附件。我对MIME树结构不熟悉,我将尝试浏览您的文档。
public static IEnumerable<FileInfo> DownloadAttachments(this EmailClient client, IMessageSummary message,
string destination)
{
fileNameFilter = fileNameFilter ?? AlwaysTrue;
if (!Directory.Exists(destination))
Directory.CreateDirectory(destination);
var folder = client.Inbox;
folder.Open(FolderAccess.ReadOnly);
foreach (var part in message.Body.GetBasicBodyParts())
{
var mimeHeader = (MimePart) folder.GetBodyPart(message.UniqueId.Value, part, headersOnly: true);
var headerFileName = mimeHeader.FileName;
if (string.IsNullOrWhiteSpace(headerFileName))
continue;
var mime = (MimePart) folder.GetBodyPart(message.UniqueId.Value, part);
var fileName = mime.FileName;
var filePath = Path.Combine(destination, fileName);
using (var stream = File.Create(filePath))
mime.ContentObject.DecodeTo(stream);
yield return new FileInfo(filePath);
}
}