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

使用Microsoft Graph获取PDF附件邮件失败:Attachments为空但HasAttachments为真

问题分析与解决办法

你的代码存在几个关键问题,导致无法正常获取并下载PDF附件,具体问题和修正方案如下:

核心问题点

  • 附件未实际加载:第一次获取邮件列表时没有通过Expand("Attachments")加载附件数据;后续发起的带Expand的请求既没加await等待完成,也没将返回的带附件邮件对象赋值给循环中的message,导致原message.Attachments始终为null。
  • 附件筛选逻辑错误:用ContentId == "application/pdf"完全错误,ContentId是附件的唯一标识ID,并非文件类型。应通过ContentType(值为application/pdf)或文件名后缀(如.pdf)来筛选PDF附件。
  • 文件名变量作用域错误:变量b定义在if块内部,每次循环都会重置为0,导致所有附件都会被命名为0file.pdf,后续文件会覆盖之前的。
  • 异步调用处理不当:使用.GetAsync().Result可能引发线程死锁,建议全程用await处理异步操作。

修正后的代码

方案一:首次请求直接加载附件(适合邮件数量不多的场景)

int fileCounter = 0;
var msgs = await _graphServiceClient.Users["abc@Turtles.com"].Messages.Request()
    .Filter("(from/emailAddress/address) eq 'noreply@adr.org'")
    .Top(5000)
    .Header("Prefer", "outlook.body-content-type='text'")
    .Expand("Attachments") // 直接加载附件,避免二次请求
    .GetAsync();

foreach (var message in msgs)
{
    if (message.HasAttachments && message.Attachments != null)
    {
        // 筛选所有PDF附件
        var pdfAttachments = message.Attachments.OfType<FileAttachment>()
            .Where(a => a.ContentType.Equals("application/pdf", StringComparison.OrdinalIgnoreCase));

        foreach (var pdfAttachment in pdfAttachments)
        {
            // 用计数器+原文件名避免重复覆盖
            string filePath = $@"C:\TMP\{fileCounter}_{pdfAttachment.Name}";
            using (var stream = new FileStream(filePath, FileMode.CreateNew))
            using (var writer = new BinaryWriter(stream))
            {
                writer.Write(pdfAttachment.ContentBytes, 0, pdfAttachment.ContentBytes.Length);
            }
            fileCounter++;
        }
    }
}

方案二:循环内单独请求带附件的邮件(适合邮件数量多,避免一次性加载大量数据)

int fileCounter = 0;
var msgs = await _graphServiceClient.Users["abc@Turtles.com"].Messages.Request()
    .Filter("(from/emailAddress/address) eq 'noreply@adr.org'")
    .Top(5000)
    .Header("Prefer", "outlook.body-content-type='text'")
    .GetAsync();

foreach (var message in msgs)
{
    if (message.HasAttachments)
    {
        // 等待异步请求完成,获取带附件的邮件对象
        var messageWithAttachments = await _graphServiceClient.Users["abc@Turtles.com"]
            .Messages[message.Id]
            .Request()
            .Expand("Attachments")
            .GetAsync();

        var pdfAttachments = messageWithAttachments.Attachments.OfType<FileAttachment>()
            .Where(a => a.ContentType.Equals("application/pdf", StringComparison.OrdinalIgnoreCase));

        foreach (var pdfAttachment in pdfAttachments)
        {
            string filePath = $@"C:\TMP\{fileCounter}_{pdfAttachment.Name}";
            using (var stream = new FileStream(filePath, FileMode.CreateNew))
            using (var writer = new BinaryWriter(stream))
            {
                writer.Write(pdfAttachment.ContentBytes, 0, pdfAttachment.ContentBytes.Length);
            }
            fileCounter++;
        }
    }
}

额外说明

  • 确保你的Graph API权限包含Mail.Read或更高权限,否则可能无法读取附件内容
  • 使用using语句自动释放文件流,避免资源泄漏
  • 若附件体积较大,可考虑通过附件的下载URL直接获取,但常规大小的PDF用ContentBytes即可满足需求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 14:45:05