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

如何通过MS Graph API回复邮件并保留历史邮件线程内容

问题描述

我正在通过UI使用MS Graph API发送回复邮件。用户会选择要回复的邮件,撰写新邮件内容并添加所需收件人(To、Cc、Bcc)。我捕获目标邮件的Message ID进行回复,邮件虽在Outlook中显示为回复链,但正文未像Outlook原生回复那样包含历史邮件线程内容。请问是否有方法实现该效果,或是我的操作存在错误?

当前实现代码:

public async Task SendReplyAsync(string EmailAccount, Email email, string MessageId)
{
    var tries = 0;
    var maxRetries = 1;

    while (tries <= maxRetries)
    {
        tries++;
        try
        {
            var ToRec = new List<Recipient>();
            foreach (var address in email.To)
            {
                ToRec.Add(
                new Recipient()
                {
                    EmailAddress = new EmailAddress
                    {
                        Address = address.EmailAddress,
                    },
                });
            }

            var CcRec = new List<Recipient>();
            foreach (var address in email.Cc)
            {
                CcRec.Add(
                new Recipient()
                {
                    EmailAddress = new EmailAddress
                    {
                        Address = address.EmailAddress,
                    },
                });
            }

            var BccRec = new List<Recipient>();
            foreach (var address in email.Bcc)
            {
                BccRec.Add(
                new Recipient()
                {
                    EmailAddress = new EmailAddress
                    {
                        Address = address.EmailAddress,
                    },
                });
            }

            var attachments = new MessageAttachmentsCollectionPage();
            foreach (var attachment in email.FileAttachments)
            {
                attachments.Add(new Microsoft.Graph.FileAttachment
                {
                    Name = attachment.FileName,
                    ContentType = attachment.ContentType,
                    ContentBytes = attachment.ContentBytes
                });
            }

            var message = new Message
            {
                Body = new ItemBody
                {
                    ContentType = Microsoft.Graph.BodyType.Html,
                    Content = email.Body,
                },
                ToRecipients = ToRec,
                CcRecipients = CcRec,
                BccRecipients = BccRec,
                Attachments = attachments,
            };

            await _graphServiceClient.Users[EmailAccount].Messages[MessageId].Reply(message, "").Request().PostAsync();

            tries = maxRetries + 1;

        }
        catch (ServiceException svcex) when (svcex.Message.Contains("Continuous access evaluation resulted in claims challenge"))
        {
            try
            {
                Console.WriteLine($"{svcex}");
                string claimChallenge = WwwAuthenticateParameters.GetClaimChallengeFromResponseHeaders(svcex.ResponseHeaders);
                _consentHandler.ChallengeUser(initialScopes, claimChallenge);
            }
            catch (Exception ex2)
            {
                _consentHandler.HandleException(ex2);
            }
        }
    }
}
解决方案

你的操作核心问题是:MS Graph API的Reply方法仅负责关联邮件线程(自动设置In-Reply-To和References头),不会自动插入原邮件的历史内容。要实现Outlook原生回复的效果,需要手动获取原邮件内容并拼接到回复正文中。

修改后的代码示例:

public async Task SendReplyAsync(string EmailAccount, Email email, string MessageId)
{
    var tries = 0;
    var maxRetries = 1;

    while (tries <= maxRetries)
    {
        tries++;
        try
        {
            // 1. 获取原邮件的关键信息:正文、发件人、接收时间
            var originalMessage = await _graphServiceClient.Users[EmailAccount].Messages[MessageId]
                .Request()
                .Select(m => new { m.Body, m.From, m.ReceivedDateTime, m.Subject })
                .GetAsync();

            // 2. 构建符合Outlook样式的原邮件引用内容
            string originalContent = string.Empty;
            if (originalMessage.Body.ContentType == BodyType.Html)
            {
                // HTML格式原邮件的引用样式
                originalContent = $@"<hr>
<p><strong>发件人:</strong> {originalMessage.From.EmailAddress.Name} &lt;{originalMessage.From.EmailAddress.Address}&gt;</p>
<p><strong>发送时间:</strong> {originalMessage.ReceivedDateTime?.ToString("yyyy-MM-dd HH:mm:ss")}</p>
<p><strong>主题:</strong> {originalMessage.Subject}</p>
<br>
{originalMessage.Body.Content}";
            }
            else
            {
                // 纯文本格式原邮件的引用样式
                originalContent = $@"

----------------------
发件人: {originalMessage.From.EmailAddress.Name} <{originalMessage.From.EmailAddress.Address}>
发送时间: {originalMessage.ReceivedDateTime?.ToString("yyyy-MM-dd HH:mm:ss")}
主题: {originalMessage.Subject}

{originalMessage.Body.Content}";
            }

            // 3. 拼接用户撰写的新内容和原邮件引用
            string replyBody = $"{email.Body}{originalContent}";

            // 以下收件人、附件处理逻辑保持不变
            var ToRec = new List<Recipient>();
            foreach (var address in email.To)
            {
                ToRec.Add(
                new Recipient()
                {
                    EmailAddress = new EmailAddress
                    {
                        Address = address.EmailAddress,
                    },
                });
            }

            var CcRec = new List<Recipient>();
            foreach (var address in email.Cc)
            {
                CcRec.Add(
                new Recipient()
                {
                    EmailAddress = new EmailAddress
                    {
                        Address = address.EmailAddress,
                    },
                });
            }

            var BccRec = new List<Recipient>();
            foreach (var address in email.Bcc)
            {
                BccRec.Add(
                new Recipient()
                {
                    EmailAddress = new EmailAddress
                    {
                        Address = address.EmailAddress,
                    },
                });
            }

            var attachments = new MessageAttachmentsCollectionPage();
            foreach (var attachment in email.FileAttachments)
            {
                attachments.Add(new Microsoft.Graph.FileAttachment
                {
                    Name = attachment.FileName,
                    ContentType = attachment.ContentType,
                    ContentBytes = attachment.ContentBytes
                });
            }

            var message = new Message
            {
                Body = new ItemBody
                {
                    ContentType = Microsoft.Graph.BodyType.Html,
                    Content = replyBody, // 使用拼接后的完整内容
                },
                ToRecipients = ToRec,
                CcRecipients = CcRec,
                BccRecipients = BccRec,
                Attachments = attachments,
            };

            await _graphServiceClient.Users[EmailAccount].Messages[MessageId].Reply(message, "").Request().PostAsync();

            tries = maxRetries + 1;

        }
        catch (ServiceException svcex) when (svcex.Message.Contains("Continuous access evaluation resulted in claims challenge"))
        {
            try
            {
                Console.WriteLine($"{svcex}");
                string claimChallenge = WwwAuthenticateParameters.GetClaimChallengeFromResponseHeaders(svcex.ResponseHeaders);
                _consentHandler.ChallengeUser(initialScopes, claimChallenge);
            }
            catch (Exception ex2)
            {
                _consentHandler.HandleException(ex2);
            }
        }
    }
}
关键说明
  • 必须主动调用Graph API获取原邮件的Body、From、ReceivedDateTime等信息,才能构建历史线程内容。
  • 代码中模拟了Outlook默认的回复引用样式,你可以根据需求调整HTML结构或纯文本格式,比如修改分隔线样式、字体颜色等。
  • 注意区分原邮件的格式(HTML/纯文本),避免格式冲突导致显示异常。

内容的提问来源于stack exchange,提问作者Qiuzman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 06:54:50