使用Microsoft Graph Client发送邮件的控制台应用故障排查求助
问题分析与解决方案
你遇到的核心问题是控制台应用中使用Async Sub导致异步操作未完成程序就提前退出。控制台的主线程不会等待Async Sub内的异步代码执行完毕,当代码执行到Await graphEmail.SendEmail(mailInfo)时会立即返回给调用者,主线程后续直接终止程序,导致邮件发送逻辑没跑完,也看不到后续调试输出和错误信息。
具体修复步骤
1. 将Async Sub改为Async Function并返回Task
Async Sub仅适用于UI事件处理场景,控制台应用必须用Async Function让调用者能等待异步操作完成:
Private Async Function SendMailAsync(ByVal sSubject As String, ByVal sTextBody As String) As Task Console.WriteLine("start to SendMail") Dim tenant As String = Configuration.ConfigurationManager.AppSettings("tenantID") Dim appID As String = Configuration.ConfigurationManager.AppSettings("appID") Dim secret As String = Configuration.ConfigurationManager.AppSettings("secretID") Dim graphEmail As MyEmail.GraphEmail = New MyEmail.GraphEmail(tenant, appID, secret) Try Dim body As String = "START TIME: " & startTime.ToString & Environment.NewLine body &= "END TIME: " & endTime.ToString & Environment.NewLine & Environment.NewLine Dim mailInfo As MyEmail.MailInfo= New MyEmail.MailInfo() mailInfo.To = Configuration.ConfigurationManager.AppSettings("TO") mailInfo.From = Configuration.ConfigurationManager.AppSettings("FROM") mailInfo.Subject = sSubject mailInfo.Body = body Dim result As String = Await graphEmail.SendEmail(mailInfo) Console.WriteLine(result) Console.ReadLine() Catch ex As Exception Console.WriteLine(ex.Message & vbCrLf & ex.StackTrace.ToString) Console.ReadLine() End Try Console.WriteLine("finished") End Function
2. 在程序入口点等待异步方法完成
根据你使用的.NET版本调整入口逻辑:
- 若为.NET Framework 4.5+:
Sub Main() ' 阻塞主线程等待异步方法完成 SendMailAsync("测试主题", "测试内容").GetAwaiter().GetResult() End Sub
- 若为.NET Core/.NET 5+,可直接使用异步入口:
Async Function Main() As Task Await SendMailAsync("测试主题", "测试内容") End Function
3. 检查GraphEmail.SendEmail的实现
确保该方法是正确的异步实现,避免使用.Wait()或.Result()这类同步阻塞调用,否则会引发死锁或异步逻辑失效。示例正确实现:
Public Async Function SendEmail(mailInfo As MailInfo) As Task(Of String) ' 初始化Graph客户端(使用ClientCredentialProvider) Dim credential = New ClientCredentialProvider(New ClientCredential(appID, secret)) Dim client = New GraphServiceClient(credential) ' 构建邮件消息 Dim message = New Message() With { .Subject = mailInfo.Subject, .Body = New ItemBody() With { .ContentType = BodyType.Text, .Content = mailInfo.Body }, .ToRecipients = { New Recipient() With { .EmailAddress = New EmailAddress() With {.Address = mailInfo.To} } } } ' 异步发送邮件 Await client.Users(mailInfo.From).SendMail(message, saveToSentItems:=True).Request().PostAsync() Return "邮件发送成功" End Function
额外调试建议
- 确认
app.config中所有配置项(tenantID、appID、secretID、TO、FROM)准确无误,FROM邮箱必须是租户内有权限的账号,且Azure AD应用已添加Mail.Send应用权限并完成管理员同意。 - 在
graphEmail.SendEmail内部添加日志输出,确认Graph API是否被成功调用。 - 查看Azure AD应用的审计日志,排查是否有API调用失败记录。
内容的提问来源于stack exchange,提问作者Y Chan
相关产品推荐
相关产品推荐

