.NET 4.7.2使用Microsoft Graph v5发送邮件大附件异常求助
问题排查与修复方案
核心问题分析
- 本地对象与远程草稿不同步:你上传大附件到草稿邮件后,仍使用最初保存的本地
savedDraft对象,该对象并未同步远程草稿的最新附件状态。后续直接给requestBody.Message.Attachments赋值新列表,会覆盖附件引用,导致发送时仅包含小附件。 - 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
相关产品推荐
相关产品推荐

