使用Microsoft Graph API发送带附件邮件报错及批量发送异常排查
问题分析与解决方案
报错Cannot process input of abstract type 'microsoft.graph.attachment'以及批量发送时仅第一个收件人成功的核心原因是:重复复用同一个SendMailPostRequestBody及内部的Message对象。Graph SDK在第一次请求序列化后,会修改对象的内部元数据状态,导致后续请求时无法正确识别具体的FileAttachment类型,转而尝试序列化抽象的Attachment基类,触发API报错。
解决步骤
- 每次循环生成全新的请求体对象,包括
Message和附件集合,避免状态残留 - 把
GraphServiceClient的创建移到循环外,减少重复初始化开销 - 简化
MemoryStream的使用,利用using自动释放资源
修改后的代码示例
private async Task ExecuteSendEmailAsync() { try { // 获取收件人列表 List<Model.User> receivers = new(); receivers.Add(new Model.User { EMAIL = "email@email.com" }); List<Reservation> reservation = new(); // 生成PDF附件字节(只做一次,复用字节数组) string contenuto = "<h1 style='text-align:center; font-family: Arial, Helvetica, sans-serif; font-size: 24px;' >Daily report</h1><br>"; contenuto += "<br>"; // 此处添加其他内容... byte[] pdfBytes; using (MemoryStream memoryStream = new MemoryStream()) { Document document = new(PageSize.A4, 10f, 10f, 10f, 0f); HtmlWorker htmlparser = new(document); PdfWriter writer = PdfWriter.GetInstance(document, memoryStream); document.Open(); htmlparser.Parse(new StringReader(contenuto)); document.Close(); pdfBytes = memoryStream.ToArray(); // using块会自动关闭memoryStream,无需手动调用Close } // 只创建一次GraphClient,避免重复初始化 GraphServiceClient graphClient = GraphHelper.GetAuthenticatedGraphClient("*tenant*"); string fromEmail = "from@email.com"; // 循环发送邮件,每次创建全新的请求体 foreach (Model.User rec in receivers) { var requestBody = new Microsoft.Graph.Users.Item.SendMail.SendMailPostRequestBody { Message = new Message { Subject = "test", Body = new ItemBody { ContentType = BodyType.Text, Content = "Hello, look at the attachment" }, ToRecipients = new List<Recipient> { new Recipient { EmailAddress = new EmailAddress { Address = rec.EMAIL } } }, Attachments = new List<Microsoft.Graph.Models.Attachment> { new FileAttachment { OdataType = "#microsoft.graph.fileAttachment", Name = "Daily_report.pdf", ContentType = "application/pdf", ContentBytes = pdfBytes, }, } } }; await graphClient.Users[fromEmail].SendMail.PostAsync(requestBody); } } catch (Exception e) { string msg = "Errore durante l'invio di una mail"; ManageExceptions.ManageLog(e, msg, "ExecuteSendEmail - ReportMensaEmailJob", "Error"); throw; } }
关键修改点
- PDF字节复用:把PDF生成逻辑移到循环外,只生成一次字节数组,提升性能
- 请求体循环内创建:每次循环都新建
SendMailPostRequestBody和Message,确保对象状态干净 - GraphClient复用:避免在循环内重复创建认证客户端,减少资源消耗
- 简化流操作:移除手动的
memoryStream.Close(),依赖using自动释放
内容的提问来源于stack exchange,提问作者Croicco
相关产品推荐
相关产品推荐

