关于Exchange Online中MailKit SMTP/IMAP已读回执的技术问询
Exchange Online已读回执相关问题解决方案
问题1:提取已读回执内容并修改邮件主题/正文
Exchange返回的已读回执格式可能不遵循标准MultipartReport结构,无法通过常规头字段检测,可按以下步骤处理:
识别已读回执邮件
- 检查Exchange专属X-Header:回执邮件通常包含
X-MS-Exchange-Organization-ReadReceipt头字段,值为True。 - 匹配主题关键字:如主题包含“已读回执”或“Read Receipt”字样。
- 检查Exchange专属X-Header:回执邮件通常包含
提取回执核心内容
- 获取邮件原始MIME内容(而非仅
HtmlBody),解析MIME结构后遍历所有文本部分,筛选包含“已打开时间”“收件人信息”等特征的内容。
- 获取邮件原始MIME内容(而非仅
修改主题与合并正文
- 在原主题前添加
Read:前缀。 - 将提取到的回执内容追加到邮件正文末尾。
- 在原主题前添加
示例代码(VB.NET,基于IMAP客户端):
' 获取邮件原始内容并解析MIME结构 Dim rawMsg = vClient.Inbox.GetMessageRaw(vItems(i).UniqueId) Dim mimeMsg = MimeMessage.Parse(rawMsg) ' 判断是否为已读回执 Dim isReadReceipt As Boolean = False ' 优先检查Exchange专属头 For Each header In mimeMsg.Headers If header.FieldName.Equals("X-MS-Exchange-Organization-ReadReceipt", StringComparison.OrdinalIgnoreCase) Then isReadReceipt = True Exit For End If Next ' 兜底检查主题关键字 If Not isReadReceipt Then isReadReceipt = mimeMsg.Subject.Contains("已读回执") OrElse mimeMsg.Subject.Contains("Read Receipt") End If If isReadReceipt Then ' 提取回执内容 Dim receiptContent As String = "" For Each part In mimeMsg.BodyParts If TypeOf part Is TextPart Then Dim textPart = CType(part, TextPart) Dim content = textPart.Text ' 匹配回执特征内容 If content.Contains("已打开") OrElse content.Contains("opened on") Then receiptContent = content Exit For End If End If Next ' 修改主题 mimeMsg.Subject = $"Read: {mimeMsg.Subject}" ' 合并回执内容到正文 If Not String.IsNullOrEmpty(receiptContent) Then Select Case mimeMsg.Body Case Is TextPart Dim bodyPart = CType(mimeMsg.Body, TextPart) bodyPart.Text = $"{bodyPart.Text}{Environment.NewLine}{receiptContent}" Case Is Multipart Dim multipart = CType(mimeMsg.Body, Multipart) multipart.Add(New TextPart("plain") With {.Text = receiptContent}) End Select End If ' 此处可根据需求保存或进一步处理修改后的邮件 End If
问题2:避免IMAP删除未读邮件时触发“未读回执”
Exchange Online的IMAP实现会在删除未读邮件时自动触发未读回执,可通过以下方式规避:
改用Graph API/EWS删除邮件
IMAP的删除机制与Exchange回执触发逻辑存在冲突,使用Exchange原生协议(Graph API或EWS)可精准控制删除行为,不会触发回执:- Graph API示例请求:
DELETE https://graph.microsoft.com/v1.0/me/messages/{message-id} - EWS简化示例代码:
Dim service As New ExchangeService(ExchangeVersion.Exchange2016) service.Credentials = New OAuthCredentials(accessToken) service.Url = New Uri("https://outlook.office365.com/EWS/Exchange.asmx") Dim item = Item.Bind(service, New ItemId("message-id")) item.Delete(DeleteMode.HardDelete)
- Graph API示例请求:
配置邮箱全局回执规则
若无法更换协议,可通过Exchange Online PowerShell指定邮箱拒绝发送任何回执:Connect-ExchangeOnline Set-Mailbox -Identity "user@domain.com" -ReadReceiptResponse NeverSend该配置会全局阻止目标邮箱发送已读/未读回执,适合无需回执功能的场景。
内容的提问来源于stack exchange,提问作者gchq
相关产品推荐
相关产品推荐

