You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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();
            }
        }
原因分析
  1. 程序挂起(死锁):
    代码在UI线程中调用Task.Wait()和Task.Result,这会阻塞当前UI线程;而Execute方法中await client.SendEmailAsync(msg).ConfigureAwait(true)会尝试将后续代码切换回原UI线程执行,但原线程已经被阻塞,导致死锁,程序无响应。
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 19:54:53