使用Microsoft Graph生成Excel后发送邮件无报错停滞求助
问题
我通过Microsoft Graph实现微软邮箱发送邮件,同时生成Excel文件作为附件发送。单独发邮件功能正常,但生成Excel后第二次调用发信代码时,程序无报错却卡在以下代码处:
var msgResult = await graphClient.Users["myemail@mycompany.com"].MailFolders.Drafts.Messages.Request().WithMaxRetry(9).AddAsync(message);
完整代码如下:
class Solds { public string Empres { get; set; } public string NClient { get; set; } public string Name { get; set; } public string PurchaseNumber { get; set; } public DateTime Date { get; set; } public string Codart { get; set; } public string Description { get; set; } public string Fampro { get; set; } public string Serpro { get; set; } public string Group { get; set; } public decimal Price { get; set; } public decimal Cost { get; set; } public string Seller { get; set; } public string Quarter { get; set; } } static void Main(string[] args) { List<String> Destinations = new List<string>() { "myemail@mycompany.com" }; List<string> Cc = new List<string>(); List<System.IO.FileInfo> Filess = new List<System.IO.FileInfo>(); List<Solds> lstSolds = GetData(); SenMailUsingMicrosoftGraph(Destinations, Cc, "", "Text of the Body", "title of the mail", Filess); // GenerateExcel creates a Excel File (i use ClosedXML) and retuns a FileInfo Filess.Add(GenerateExcel(lstSolds)); SenMailUsingMicrosoftGraph(Destinations, Cc, "", "Text of the Body", "title of the mail", Filess); } private static async void SenMailUsingMicrosoftGraph(List<String>Destinations, List<String>Cc, string HidenCopy, string Body, string Title, List<FileInfo>Filess) { ClientSecretCredential credential = new ClientSecretCredential("MyTenantID", "MyClientId", "MyClientSecret"); List<Recipient> recipientsDestinatarios = new List<Recipient>(); List<Recipient> recipientsCopias = new List<Recipient>(); foreach (var c in Destinations) { recipientsDestinatarios.Add( new Recipient { EmailAddress = new EmailAddress { Address = c } }); } foreach (var mail in Cc) { recipientsCopias.Add( new Recipient { EmailAddress = new EmailAddress { Address = mail } }); } var message = new Microsoft.Graph.Message { Subject = Title, Body = new ItemBody { ContentType = BodyType.Html, Content = Body }, ToRecipients = recipientsDestinatarios, CcRecipients = recipientsCopias, BccRecipients = new List<Recipient>() { new Recipient { EmailAddress=new EmailAddress{Address=Hiden} } } }; GraphServiceClient graphClient = new GraphServiceClient(credential); var msgResult = await graphClient.Users["myemail@mycompany.com"].MailFolders.Drafts.Messages .Request() .WithMaxRetry(9) .AddAsync(message); foreach (var Archivo in Filess) { var attachmentContentSize = Archivo.Length; var attachmentItem = new AttachmentItem { AttachmentType = AttachmentType.File, Name = Archivo.Name, Size = attachmentContentSize, }; //initiate the upload session for large files var uploadSession = await graphClient.Users["myemail@mycompany.com"].Messages[msgResult.Id].Attachments .CreateUploadSession(attachmentItem) .Request() .PostAsync(); var maxChunkSize = 1024 * 320; var allBytes = System.IO.File.ReadAllBytes(Archivo.FullName); using (var stream = new MemoryStream(allBytes)) { stream.Position = 0; LargeFileUploadTask<FileAttachment> largeFileUploadTask = new LargeFileUploadTask<FileAttachment>(uploadSession, stream, maxChunkSize); await largeFileUploadTask.UploadAsync(); } } await graphClient.Users["myemail@mycompany.com"].Messages[msgResult.Id].Send().Request().PostAsync(); } private static FileInfo GenerateExcel(List<Solds> lstSolds) { System.IO.FileInfo file= new System.IO.FileInfo(@"E:\MyFolder\MyFile.xlsx"); if (file.Exists) file.Delete(); using (var wb = new XLWorkbook()) { var ws = wb.Worksheets.Add("Example"); ws.Cell(2, 1).InsertTable(lstSolds); wb.SaveAs(file.FullName); } return file; } private static List<Solds> GetData() { List<Solds> lstSolds = new List<Solds>(); string connString = @"Data Source=MyServer\SQLExpress; Initial Catalog=MyDataBAse;User Id=User;Password=password;"; string sentenciaSQL = "QuarterSolds"; using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(connString)) { using (SqlCommand comm = new SqlCommand(sentenciaSQL, conn)) { DateTime t = DateTime.Now; conn.Open(); comm.CommandType = System.Data.CommandType.StoredProcedure; comm.CommandTimeout = 240; using (SqlDataReader reader = comm.ExecuteReader()) { if (reader.HasRows) { while (reader.Read()) { Solds v = new Solds(); decimal d = 0; v.Empres = reader.GetValue(0).ToString(); v.NClient = reader.GetValue(1).ToString(); v.Name = reader.GetValue(2).ToString(); v.PurchaseNumber = reader.GetValue(3).ToString(); v.Date = DateTime.TryParse(reader.GetValue(4).ToString(), out t) ? t : t; v.Codart = reader.GetValue(5).ToString(); v.Description = reader.GetValue(6).ToString(); v.Fampro = reader.GetValue(7).ToString(); v.Serpro = reader.GetValue(8).ToString(); v.Group = reader.GetValue(9).ToString(); v.Price = decimal.TryParse(reader.GetValue(10).ToString(), out d) ? d : 0; v.Cost = decimal.TryParse(reader.GetValue(11).ToString(), out d) ? d : 0; v.Seller = reader.GetValue(12).ToString(); v.Quarter = reader.GetValue(13).ToString(); lstSolds.Add(v); } } else Console.WriteLine("No lines"); } } } return lstSolds; }
解决建议
1. 修复async void的异步调用问题
SenMailUsingMicrosoftGraph方法使用async void会导致控制台程序主线程不等待异步操作完成,甚至引发线程阻塞。改为async Task,同时将Main方法改为异步:
static async Task Main(string[] args) { List<String> Destinations = new List<string>() { "myemail@mycompany.com" }; List<string> Cc = new List<string>(); List<System.IO.FileInfo> Filess = new List<System.IO.FileInfo>(); List<Solds> lstSolds = GetData(); await SenMailUsingMicrosoftGraph(Destinations, Cc, "", "Text of the Body", "title of the mail", Filess); Filess.Add(GenerateExcel(lstSolds)); await SenMailUsingMicrosoftGraph(Destinations, Cc, "", "Text of the Body", "title of the mail", Filess); } private static async Task SenMailUsingMicrosoftGraph(List<String> Destinations, List<String> Cc, string HidenCopy, string Body, string Title, List<FileInfo> Filess) { // 原有代码逻辑不变 }
这是导致程序停滞的核心原因,async void的异步异常无法被正常捕获,会导致程序静默挂起。
2. 修正Bcc收件人变量错误
代码中BccRecipients使用了未定义的Hiden变量,应替换为方法参数HidenCopy,否则会引发编译错误或空地址问题,间接导致草稿创建请求阻塞:
BccRecipients = new List<Recipient>() { new Recipient { EmailAddress=new EmailAddress{Address=HidenCopy} } }
3. 验证Excel文件是否被占用
GenerateExcel生成文件后,可能存在未释放的句柄导致文件被锁定。添加文件可访问性验证:
var excelFile = GenerateExcel(lstSolds); // 验证文件未被占用 using (var stream = excelFile.Open(FileMode.Open, FileAccess.Read, FileShare.None)) { // 无异常则说明文件可正常读取 } Filess.Add(excelFile);
4. 添加异常捕获与日志
在停滞的代码块周围添加异常捕获,输出详细错误信息,排查异步操作中的静默异常:
try { var msgResult = await graphClient.Users["myemail@mycompany.com"].MailFolders.Drafts.Messages .Request() .WithMaxRetry(9) .AddAsync(message); } catch (Exception ex) { Console.WriteLine($"创建草稿失败: {ex.Message}"); if (ex.InnerException != null) { Console.WriteLine($"内部异常: {ex.InnerException.Message}"); } throw; }
5. 复用Graph客户端实例
每次调用发信方法都新建GraphServiceClient和ClientSecretCredential会增加认证开销,改为单例复用:
private static readonly ClientSecretCredential _credential = new ClientSecretCredential("MyTenantID", "MyClientId", "MyClientSecret"); private static readonly GraphServiceClient _graphClient = new GraphServiceClient(_credential); // 在SenMailUsingMicrosoftGraph方法中直接使用_graphClient
内容的提问来源于stack exchange,提问作者Ion
相关产品推荐
相关产品推荐

