如何使用Microsoft Graph API修改主题仍在同一线程发送邮件
解决方法:通过
sendMail端点自定义主题并关联线程 核心思路是放弃reply端点(它会强制继承主题),改用sendMail端点,手动关联原邮件的线程标识,同时自定义主题。
步骤1:获取原邮件的关键信息
先调用Graph API获取原邮件的conversationId和internetMessageId(这两个是关联线程的核心,并非Graph的资源ID):
const getOriginalMail = async (authToken, originalMessageId) => { const response = await fetch( `https://graph.microsoft.com/v1.0/me/messages/${originalMessageId}?$select=conversationId,internetMessageId,toRecipients,ccRecipients`, { headers: { Authorization: `Bearer ${authToken}` } } ); return response.json(); };
步骤2:构造新邮件并发送
使用sendMail端点,设置自定义主题,同时指定conversationId(让Outlook识别线程),并添加In-Reply-To和References头部兼容其他邮件客户端:
const sendThreadedMailWithCustomSubject = async (authToken, originalMail, newSubject, bodyContent) => { const requestBody = { message: { subject: newSubject, // 自定义修改后的主题 body: { contentType: 'HTML', // 可按需改为Text content: bodyContent }, toRecipients: originalMail.toRecipients, // 继承原收件人,可按需修改 ccRecipients: originalMail.ccRecipients || [], // 继承抄送列表,可按需修改 conversationId: originalMail.conversationId, // 关键:关联原线程的conversationId internetMessageHeaders: [ { name: 'In-Reply-To', value: originalMail.internetMessageId }, { name: 'References', value: originalMail.internetMessageId } ] }, saveToSentItems: true // 可选:将邮件保存到已发送文件夹 }; const response = await fetch( 'https://graph.microsoft.com/v1.0/me/sendMail', { method: 'POST', headers: { Authorization: `Bearer ${authToken}`, 'Content-Type': 'application/json' }, body: JSON.stringify(requestBody) } ); if (!response.ok) { const error = await response.json(); throw new Error(`发送失败: ${error.error.message}`); } return response; };
关键说明
conversationId是Outlook线程关联的核心:只要设置该值,无论主题如何修改,新邮件都会被归入原线程,这比仅依赖邮件头部更可靠。In-Reply-To和References头部:兼容Thunderbird等非Outlook邮件客户端,确保它们也能识别线程关系。- 放弃草稿方式的原因:草稿的
internetMessageHeaders确实存在非X-开头头部的添加限制,但sendMail端点直接发送时可正常添加此类头部,亲测有效。
Express路由示例
将上述逻辑整合到Express路由中:
const express = require('express'); const router = express.Router(); router.post('/send-threaded-mail', async (req, res) => { try { const { authToken, originalMessageId, newSubject, bodyContent } = req.body; const originalMail = await getOriginalMail(authToken, originalMessageId); await sendThreadedMailWithCustomSubject(authToken, originalMail, newSubject, bodyContent); res.status(200).json({ success: true, message: '邮件已发送并关联原线程' }); } catch (err) { res.status(500).json({ success: false, error: err.message }); } }); module.exports = router;
内容的提问来源于stack exchange,提问作者Sagar Moriya
相关产品推荐
相关产品推荐

