使用SendGrid API发送邮件时C#程序挂起问题求助
问题描述
使用.NET Framework 4.7 + SendGrid 9.28.1通过API发送邮件时,程序无响应挂起;改用SendGrid SMTP发送正常;将ConfigureAwait(true)改为ConfigureAwait(false)后,抛出如下异常:
An error occurred while sending the request. - at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at SendGrid.Helpers.Reliability.RetryDelegatingHandler.<SendAsync>d__3.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at SendGrid.BaseClient.<MakeRequest>d__20.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at SendGrid.BaseClient.<RequestAsync>d__21.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at SendGrid.BaseClient.<SendEmailAsync>d__22.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult() at EasyWhatsappSender.Classes.EmailClasses.SenderEmailClasses.SendGridSender.<Execute>d__1.MoveNext() in E:\my projects do not delete it\EasySender\Classes\EmailClasses\SenderEmailClasses\SendGridSender.cs:line 64
原代码如下:
using SendGrid; using SendGrid.Helpers.Mail; public static string Send( string APIKey, string Message, string SenderEmail, List<string> Receivers, string Subject) { try { Task<string> b = Execute(APIKey, Message, SenderEmail, Receivers, Subject); b.Wait(); if (b.Result == "True") { return "True"; } else { return b.Result; } } catch (Exception ex) { return ex.Message + " - " + ex.StackTrace.ToString(); } } private static async Task<string> Execute( string APIKey, string Message, string SenderEmail, List<string> Receivers, string Subject) { try { var client = new SendGridClient(APIKey); var from = new EmailAddress(SenderEmail); var subject = Subject; var to = new EmailAddress(Receivers[0]); var plainTextContent = Message; var htmlContent = "<strong>" + Message + "</strong>"; var msg = MailHelper.CreateSingleEmail(from, to, subject, plainTextContent, htmlContent); MessageBox.Show("before"); var response = await client.SendEmailAsync(msg).ConfigureAwait(true); return response.IsSuccessStatusCode + ""; } catch (Exception ex) { MessageBox.Show(ex.Message + " - " + ex.StackTrace.ToString()); return ex.Message + " - " + ex.StackTrace.ToString(); } }
原因分析
- 程序挂起(死锁):
代码在UI线程中调用Task.Wait()和Task.Result,这会阻塞当前UI线程;而Execute方法中await client.SendEmailAsync(msg).ConfigureAwait(true)会尝试将后续代码切换回原UI线程执行,但原线程已经被阻塞,导致死锁,程序无响应。 - ConfigureAwait(false)报错:
设置ConfigureAwait(false)后,异步操作完成后不会切回原UI线程,后续的MessageBox.Show尝试在非UI线程访问UI控件,引发跨线程操作异常;同时底层的请求错误("An error occurred while sending the request")可能还涉及网络环境、API密钥权限或SendGrid客户端配置问题。
解决方案
方案1:彻底异步化(推荐)
将Send方法改为异步方法,全程使用异步调用避免阻塞UI线程:
using SendGrid; using SendGrid.Helpers.Mail; using System.Threading.Tasks; using System.Windows; public static async Task<string> SendAsync( string APIKey, string Message, string SenderEmail, List<string> Receivers, string Subject) { try { return await ExecuteAsync(APIKey, Message, SenderEmail, Receivers, Subject); } catch (Exception ex) { // 跨线程调用UI控件需切换回UI线程 Application.Current.Dispatcher.Invoke(() => MessageBox.Show(ex.Message + " - " + ex.StackTrace.ToString())); return ex.Message + " - " + ex.StackTrace.ToString(); } } private static async Task<string> ExecuteAsync( string APIKey, string Message, string SenderEmail, List<string> Receivers, string Subject) { try { var client = new SendGridClient(APIKey); var from = new EmailAddress(SenderEmail); var subject = Subject; var to = new EmailAddress(Receivers[0]); var plainTextContent = Message; var htmlContent = "<strong>" + Message + "</strong>"; var msg = MailHelper.CreateSingleEmail(from, to, subject, plainTextContent, htmlContent); // 在UI线程显示弹窗 Application.Current.Dispatcher.Invoke(() => MessageBox.Show("before")); var response = await client.SendEmailAsync(msg).ConfigureAwait(false); return response.IsSuccessStatusCode.ToString(); } catch (Exception ex) { Application.Current.Dispatcher.Invoke(() => MessageBox.Show(ex.Message + " - " + ex.StackTrace.ToString())); return ex.Message + " - " + ex.StackTrace.ToString(); } }
调用时使用await SendAsync(...),确保调用方也是异步方法(比如UI事件处理方法标记为async void)。
方案2:同步调用避免死锁(不推荐)
如果无法修改为异步,可通过Task.Run将异步操作移到后台线程,避免阻塞UI线程:
public static string Send( string APIKey, string Message, string SenderEmail, List<string> Receivers, string Subject) { try { // 把异步操作放到后台线程执行,避免UI线程死锁 return Task.Run(() => ExecuteAsync(APIKey, Message, SenderEmail, Receivers, Subject)).Result; } catch (Exception ex) { MessageBox.Show(ex.Message + " - " + ex.StackTrace.ToString()); return ex.Message + " - " + ex.StackTrace.ToString(); } }
额外检查项
- 确认SendGrid API密钥拥有发送邮件的权限,且未被限制
- 检查服务器/客户端网络是否能访问SendGrid API端点(
https://api.sendgrid.com),可通过浏览器或curl测试连通性 - 升级SendGrid NuGet包到针对.NET Framework 4.7的最新稳定版本
内容的提问来源于stack exchange,提问作者Fath Bakri
相关产品推荐
相关产品推荐

