在 Exchange Server 的日常运维与开发中,一个常见却容易被忽视的需求是:发送一封电子邮件,并将另一封已有的电子邮件以附件形式嵌入其中。例如,企业需要将客户的投诉邮件作为证据转发给审核部门,或需要归档邮件时保留完整的原始邮件格式。这一问题在 Exchange Web Services(EWS) API 社区中频繁被提及,标题“EWS request - How to send an email with another email in attachment?” 正是这一需求的真实写照。本文将深入解析该问题,并给出基于 EWS 的完整解决方案。
一、需求背景:为什么需要“邮件附件邮件”?
在传统邮件客户端中,用户可以直接拖动邮件到新邮件窗口,生成一个 .eml 或 .msg 文件作为附件。但在自动化场景中,例如企业级工作流、客服系统或合规审计平台,需要通过程序化方式实现这一操作。EWS 作为 Exchange 的主要编程接口,常被用于批量邮件处理。然而,很多开发者发现:直接使用 ItemAttachment 将邮件对象附加到另一封邮件时,附件在 Outlook 中显示为“邮件项”,但无法在非 Outlook 客户端正确读取;而如果将其转换为 .eml 格式的字节流,又可能丢失 Exchange 特有的属性(如类别、敏感度等)。如何平衡通用性与完整性,成为核心难点。
二、核心思路:将邮件项序列化为 MIME 流
EWS 提供了两种附件类型:FileAttachment(文件附件)和 ItemAttachment(邮件项附件)。前者适合附加任意文件(包括 .eml 文件),后者则支持在 Exchange 环境内保留邮件对象的完整结构(包括所有扩展属性)。综合来看,推荐的做法是:先获取原始邮件项的 MIME 内容,将其作为 FileAttachment 添加到新邮件中。这样做出的附件在任何邮件客户端中均可被识别为可转发的邮件文件,且不依赖 Exchange 环境。
具体步骤分为三步:
-
获取原始邮件的 MIME 流
通过 EWS 的GetItem操作,请求MimeContent属性。该属性返回邮件的完整 MIME 表示(Base64 编码的字节流)。注意:需要确保请求的ItemShape包含MimeContent。 -
创建新邮件并添加文件附件
创建EmailMessage对象,设置收件人、主题、正文等。然后使用Attachments.AddFileAttachment方法,将第一步获得的 MIME 流作为附件添加。附件名称建议使用OriginalSubject.eml,以便收件人双击打开。 -
发送邮件
调用EmailMessage.SendAndSaveCopy方法发送并保存到已发送文件夹。
三、代码示例(C# 伪码)
// 1. 获取原始邮件的 MIME 内容
var originalEmail = EmailMessage.Bind(service, originalItemId,
new PropertySet(ItemSchema.MimeContent));
byte[] mimeBytes = originalEmail.MimeContent.Content;
// 2. 构建新邮件
EmailMessage newEmail = new EmailMessage(service);
newEmail.ToRecipients.Add("recipient@contoso.com");
newEmail.Subject = "Fwd: " + originalEmail.Subject;
newEmail.Body = new MessageBody(BodyType.Text, "请查收附件中的原始邮件。");
// 3. 添加附件(文件名必须为 .eml)
string attachmentName = originalEmail.Subject + ".eml";
newEmail.Attachments.AddFileAttachment(attachmentName, mimeBytes);
// 4. 发送
newEmail.SendAndSaveCopy();
四、注意事项与常见陷阱
- 权限问题:调用
GetItem时,执行账户需对原始邮件具有至少“读取”权限。若邮件位于他人邮箱,可使用模拟(Impersonation)或委托访问。 - 附件大小限制:Exchange Online 默认附件大小上限为 25MB,本地 Exchange 可通过传输设置调整。如果原始邮件包含内嵌图片或大型附件,MIME 流可能超限。
- 字符编码:MIME 流中的标题可能包含非 ASCII 字符,建议在设置附件名称时进行 URL 编码或使用
ExtendedProperty存储原始名称。 - 性能优化:如需批量处理,考虑使用
CreateItems批量创建邮件,避免多次往返。
五、替代方案:使用 ItemAttachment 的局限
部分开发者尝试直接使用 ItemAttachment 附加邮件项。在 EWS 中,可通过 Attachments.AddItemAttachment 将现有邮件引用(而不是内容)附加到新邮件。这种方法生成的附件在 Outlook 中显示为“此项目中包含的其他项目”,但其他客户端(如 Gmail、Thunderbird)可能无法正确处理,因为非 Exchange 客户端需要将邮件项导出为 .eml 才能读取。因此,从通用性出发,MIME 方案更优。
六、行业应用与展望
随着混合办公和自动化流程的普及,“邮件附件邮件”这一操作已经渗透到多个领域: - 客户服务:自动将客户历史邮件作为附件转发至负责人。 - 法律合规:在邮件归档过程中保留原始邮件元数据。 - 系统集成:通过 EWS 将邮件内容导入第三方 CRM 或工单系统。
微软在最新发布的 Graph API 中,通过 Message Create 支持直接添加 .eml 附件,与 EWS 的 MIME 方案一脉相承。对于仍在使用 EWS 的旧项目,上述方案仍是稳定可靠的选择。
结语
“如何将邮件作为附件发送”看似简单,实则涉及邮件协议、API 特性与客户端兼容性的多方平衡。本文提供的 MIME 流方案已在多个企业级项目中验证,既能保证附件在 Outlook 中可双击打开,也能确保在其他客户端中以标准 .eml 文件显示。建议开发者在实施前根据自身环境测试附件的大小和权限边界,从而获得最佳体验。