如何使用MailKit/MimeKit转移邮件附件?基于ImapClient与目标邮件UniqueId的实现方法
嘿,这个问题我刚好实操过,用MailKit和MimeKit来转移邮件附件其实没那么复杂,我给你拆解成通用逻辑+结合ImapClient UniqueId的完整流程,连代码示例都给你备好:
一、通用的附件转移核心逻辑
不管你是已经拿到了原邮件的MimeMessage实例,还是从本地文件加载的邮件,核心步骤都是「提取原邮件附件 → 添加到新邮件」:
1. 提取原邮件中的附件
首先要从原MimeMessage里筛选出真正的附件(要区分开邮件里的内嵌图片这类资源):
var originalMessage = ...; // 你的原邮件MimeMessage实例 var attachments = originalMessage.Attachments .Where(part => part.ContentDisposition?.DispositionType == DispositionTypeNames.Attachment) .ToList();
注意:如果不想区分内嵌资源,直接用originalMessage.Attachments就行,但这样会把邮件里的内嵌图片也当成附件转移过去,按需选择~
2. 创建新邮件并添加附件
接下来创建新的MimeMessage,把提取到的附件加进去:
var newMessage = new MimeMessage(); newMessage.From.Add(new MailboxAddress("发件人", "sender@example.com")); newMessage.To.Add(new MailboxAddress("收件人", "recipient@example.com")); newMessage.Subject = "转存附件的新邮件"; // 构建邮件内容(正文+附件) var bodyBuilder = new BodyBuilder(); bodyBuilder.TextBody = "这是转移过来的附件:"; // 把每个附件添加到新邮件 foreach (var attachment in attachments) { // 直接添加原附件的MimePart,会保留原文件名、格式等属性 bodyBuilder.Attachments.Add(attachment); } newMessage.Body = bodyBuilder.ToMessageBody();
二、结合ImapClient和UniqueId的完整流程
如果你是通过ImapClient拿到了目标邮件的UniqueId,那完整流程还要加上「从IMAP服务器获取指定邮件」这一步,具体步骤如下:
1. 连接IMAP服务器并登录
using var client = new ImapClient(); await client.ConnectAsync("imap.example.com", 993, SecureSocketOptions.SslOnConnect); await client.AuthenticateAsync("your-email@example.com", "your-password-or-app-password");
2. 选择目标文件夹并获取指定UniqueId的邮件
// 选择收件箱(或者你存放目标邮件的文件夹) var inbox = client.Inbox; await inbox.OpenAsync(FolderAccess.ReadOnly); // 通过UniqueId获取完整邮件(如果邮件很大,也可以先Fetch结构再按需下载附件,下面会提) var originalMessage = await inbox.GetMessageAsync(uniqueId);
高效优化:如果邮件体积很大,不想下载完整邮件,可以先Fetch邮件的BodyStructure,再单独下载附件:
// 先获取邮件的结构信息 var summary = await inbox.FetchAsync(uniqueId, MessageSummaryItems.BodyStructure); var bodyStructure = summary[0].BodyStructure; // 遍历结构找到附件部分,单独下载 foreach (var part in bodyStructure.OfType<MimePart>().Where(p => p.ContentDisposition?.DispositionType == DispositionTypeNames.Attachment)) { var attachmentStream = new MemoryStream(); await inbox.GetPartAsync(uniqueId, part, attachmentStream); // 把attachmentStream转成MimePart添加到新邮件 var attachment = new MimePart(part.ContentType.MediaType, part.ContentType.MediaSubtype) { Content = new MimeContent(attachmentStream), ContentDisposition = part.ContentDisposition, ContentTransferEncoding = part.ContentTransferEncoding, FileName = part.FileName }; bodyBuilder.Attachments.Add(attachment); }
3. 转移附件并发送/保存新邮件
拿到原邮件的附件后,就可以按照上面通用逻辑的步骤创建新邮件,然后发送或者保存到邮箱:
// 发送新邮件(用SmtpClient) using var smtpClient = new SmtpClient(); await smtpClient.ConnectAsync("smtp.example.com", 587, SecureSocketOptions.StartTls); await smtpClient.AuthenticateAsync("your-email@example.com", "your-password"); await smtpClient.SendAsync(newMessage); await smtpClient.DisconnectAsync(true); // 或者保存到IMAP服务器的指定文件夹 var sentFolder = client.GetFolder(SpecialFolder.Sent); await sentFolder.AppendAsync(newMessage, MessageFlags.Seen);
一些额外提示
- 如果你需要保留附件的原始文件名、ContentId等属性,直接复用原
MimePart实例是最稳妥的,不要自己重新构建,避免丢失信息 - 处理大附件时,用
GetPartAsync单独下载附件比下载完整邮件更节省带宽和内存 - 如果要批量转移多封邮件的附件,只需要遍历UniqueId列表重复上述步骤即可
内容的提问来源于stack exchange,提问作者SpiritBob
相关产品推荐
相关产品推荐

