You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 09:10:04