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

.NET 4.7.2使用Microsoft Graph v5发送邮件大附件异常求助

问题排查与修复方案

核心问题分析

  1. 本地对象与远程草稿不同步:你上传大附件到草稿邮件后,仍使用最初保存的本地savedDraft对象,该对象并未同步远程草稿的最新附件状态。后续直接给requestBody.Message.Attachments赋值新列表,会覆盖附件引用,导致发送时仅包含小附件。
  2. BCC逻辑错误:循环处理BCC收件人时,错误将其添加到了CC列表中。

修复后的代码实现

调整流程为:创建完整内容的草稿→上传大附件到草稿→添加小附件到草稿→直接发送草稿,避免本地对象与远程数据不同步的问题:

using Microsoft.Graph;
using Microsoft.Graph.Models;
using System.IO;
using Azure.Identity;
using System.Linq;

public async void SendEmailWithAttachments()
{
    // 填充配置信息
    string tenantID = "<insert tenant ID>";
    string clientID = "<insert client ID>";
    string secret = "<insert secret>";
    string objectID = "<insert object id of the user and not the application>";
    string EmailSubject = "Testing Email of Microsoft Graph Send Email with Attachments";
    string EmailBody = "I really wish I could actually see the large attachments that I am uploading.";
    List<string> EmailTo = new List<string>();
    List<string> EmailCC = new List<string>();
    List<string> EmailBCC = new List<string>();
    FileInfo littleAttachment = new FileInfo(@"c:\example\smallfile.txt");
    FileInfo bigAttachment = new FileInfo(@"c:\example\BigFile.jpg");

    EmailTo.Add("YourEmail@exampleOfYourEmail.com");

    var cred = new ClientSecretCredential(tenantID, clientID, secret, new TokenCredentialOptions { AuthorityHost = AzureAuthorityHosts.AzurePublicCloud });
    GraphServiceClient graphClient = new GraphServiceClient(cred);

    // 1. 创建包含完整邮件内容的草稿
    var draftMessage = new Message
    {
        Subject = EmailSubject,
        Body = new ItemBody
        {
            ContentType = BodyType.Text,
            Content = EmailBody
        },
        ToRecipients = EmailTo.Select(to => new Recipient { EmailAddress = new EmailAddress { Address = to } }).ToList(),
        CcRecipients = EmailCC.Select(cc => new Recipient { EmailAddress = new EmailAddress { Address = cc } }).ToList(),
        BccRecipients = EmailBCC.Select(bcc => new Recipient { EmailAddress = new EmailAddress { Address = bcc } }).ToList()
    };

    var savedDraft = await graphClient.Users[objectID].Messages.PostAsync(draftMessage);
    var draftId = savedDraft.Id;

    // 2. 上传大附件到草稿
    using (var fileStream = File.OpenRead(bigAttachment.FullName))
    {
        var uploadRequestBody = new Microsoft.Graph.Users.Item.Messages.Item.Attachments.CreateUploadSession.CreateUploadSessionPostRequestBody
        {
            AttachmentItem = new AttachmentItem
            {
                AttachmentType = AttachmentType.File,
                Name = bigAttachment.Name,
                Size = fileStream.Length,
                ContentType = "image/jpeg" // 使用文件对应的正确ContentType
            }
        };

        var uploadSession = await graphClient.Users[objectID]
            .Messages[draftId]
            .Attachments
            .CreateUploadSession
            .PostAsync(uploadRequestBody);

        int maxSliceSize = 320 * 1024;
        var fileUploadTask = new LargeFileUploadTask<FileAttachment>(uploadSession, fileStream, maxSliceSize);

        var totalLength = fileStream.Length;
        IProgress<long> progress = new Progress<long>(prog =>
        {
            Console.WriteLine($"Uploaded {prog} bytes of {totalLength} bytes");
        });

        try
        {
            var uploadResult = await fileUploadTask.UploadAsync(progress);
            Console.WriteLine(uploadResult.UploadSucceeded ? "Big attachment upload complete" : "Big attachment upload failed");
        }
        catch (ServiceException ex)
        {
            Console.WriteLine($"Error uploading big attachment: {ex.ToString()}");
            return;
        }
    }

    // 3. 添加小附件到草稿
    byte[] littleStream = File.ReadAllBytes(littleAttachment.FullName);
    var smallAttachment = new FileAttachment
    {
        Name = littleAttachment.Name,
        ContentBytes = littleStream,
        ContentType = "text/plain" // 使用文件对应的正确ContentType
    };

    await graphClient.Users[objectID].Messages[draftId].Attachments.PostAsync(smallAttachment);

    // 4. 发送草稿并可选删除草稿(对应原SaveToSentItems=false)
    try
    {
        await graphClient.Users[objectID].Messages[draftId].Send.PostAsync();
        Console.WriteLine("Email sent successfully with all attachments");
        await graphClient.Users[objectID].Messages[draftId].DeleteAsync();
    }
    catch (ServiceException ex)
    {
        Console.WriteLine($"Error sending email: {ex.ToString()}");
    }
}

关键优化点

  • 先创建包含完整收件人、主题、正文的草稿,避免后续修改本地对象导致的同步问题
  • 所有附件直接添加到远程草稿中,确保数据一致性
  • 使用草稿的Send接口直接发送,保证所有附件都被包含
  • 为附件指定正确的ContentType,提升邮件客户端的文件识别兼容性
  • 发送后删除草稿,实现原代码中SaveToSentItems = false的效果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 02:27:09