发送批量邮件时遇错误:异步调用已在进行中需完成或取消
解决SmtpClient异步调用冲突的问题
嘿,这个问题我之前做批量邮件发送的时候也踩过一模一样的坑!咱们来一步步拆解原因和解决方案:
问题根源
你遇到的错误“异步调用已在进行中,必须完成或取消后才能调用此方法”,本质是因为**System.Net.Mail.SmtpClient的实例不是线程安全的**。当你用同一个smtp实例同时发起多个SendMailAsync调用时,客户端会尝试复用同一个网络连接,导致并发调用之间互相干扰,触发这个错误。
解决方案1:为每封邮件创建独立的SmtpClient实例
最简单的修复方式,就是让每个异步任务都使用自己的SmtpClient实例,这样就不会有连接冲突的问题。同时用using语句确保资源被正确释放:
public static async Task<bool> SendRegisterEmail(List<MailMessage> mailMessage) { bool flag = true; try { // 给每封邮件分配独立的SmtpClient实例 var emailTasks = mailMessage.Select(async message => { using var smtp = new SmtpClient(); // 这里可以根据你的配置设置SMTP服务器、端口、凭据等 // smtp.Host = "your-smtp-server.com"; // smtp.Port = 587; // smtp.Credentials = new NetworkCredential("username", "password"); // smtp.EnableSsl = true; await smtp.SendMailAsync(message); }); await Task.WhenAll(emailTasks); } catch (Exception ex) { flag = false; // 记得这里添加日志记录或者异常处理逻辑 Console.WriteLine($"邮件发送失败: {ex.Message}"); } return flag; }
解决方案2:改用更现代的MailKit库
官方其实已经标记System.Net.Mail.SmtpClient为过时(Obsolete),推荐使用更可靠、线程安全的第三方库MailKit。它不仅支持并发发送,还提供了更丰富的邮件处理功能:
- 首先通过NuGet安装MailKit:
Install-Package MailKit - 修改你的代码为以下形式:
using MailKit.Net.Smtp; using MimeKit; public static async Task<bool> SendRegisterEmail(List<MimeMessage> mimeMessages) { bool flag = true; try { using var smtp = new SmtpClient(); // 连接到SMTP服务器 await smtp.ConnectAsync("your-smtp-server.com", 587, MailKit.Security.SecureSocketOptions.StartTls); // 验证身份 await smtp.AuthenticateAsync("your-email@example.com", "your-password"); // MailKit的SmtpClient支持并发调用SendAsync var emailTasks = mimeMessages.Select(message => smtp.SendAsync(message)); await Task.WhenAll(emailTasks); // 断开连接 await smtp.DisconnectAsync(true); } catch (Exception ex) { flag = false; Console.WriteLine($"邮件发送失败: {ex.Message}"); } return flag; }
注意:这里需要把原来的MailMessage转换成MimeMessage,MailKit提供了便捷的转换方式,或者你可以直接用MimeMessage构建邮件内容。
总结
- 如果只是临时修复现有代码,方案1足够简单直接;
- 如果是长期维护的项目,强烈推荐方案2,MailKit是目前.NET生态中处理邮件的首选库,稳定性和功能都远超原生的SmtpClient。
内容的提问来源于stack exchange,提问作者Vatsal Patel
相关产品推荐
相关产品推荐

