发送多线程 SMTP 电子邮件

本文关键字:电子邮件 SMTP 多线程 | 更新日期: 2023-09-27 18:31:09

我开发了一个主要使用SMTP发送电子邮件的应用程序。

MailMessage mail = new MailMessage();
mail.From = new MailAddress("from", "to");
mail.Subject = "subject";
mail.Body = "body";
SmtpClient client = new SmtpClient("my domain");
client.Credentials = new NetworkCredential(from, "MyPass");
client.Send(mail);

这工作正常,但现在我想同时发送几条消息而无需等待,所以我将所有消息都放在一个列表中:

List<MailMessage> emails = new List<MailMessage>();
emails.Add(new MailMessage (...));
emails.Add(new MailMessage (...));
emails.Add(new MailMessage (...));
...

我想打开每封电子邮件的新Thread

// Generate and execute all mails concurrently
var emailTasks = emails.Select(msg =>
                 {
                     client = new SmtpClient();
                     return client.SendAsync(msg);
                 });
// Asynchronously wait for all of them to complete.
await Task.WhenAll(emailTasks);

并得到此错误:

没有 SendMailAsync,并且最后一行代码也出现错误: "await"运算符只能在异步方法中使用。考虑 使用"async"修饰符标记此方法并更改其返回值 键入"任务"

发送多线程 SMTP 电子邮件

发生此错误的原因是您在所有线程捕获的同一SmtpClient实例上进行多个 SMTP 调用。

您可以在SmtpClient.Send的源代码中看到它(为简洁起见,缩短):

try 
{
    // If there is already an ongoing SMTP request
    if (InCall)
    {
        throw new InvalidOperationException(SR.GetString(SR.net_inasync));
    }
}

通常,不需要使用任何线程来执行 I/O 绑定操作,因为它们本质上是异步的。

相反,您可以使用async-await来利用异步 API:

// Generate and execute all mails concurrently
var emailTasks = emails.Select(msg => 
                 {
                    var client = new SmtpClient();
                    return client.SendMailAsync(msg));
                 });
// Asynchronously wait for all of them to complete.
await Task.WhenAll(emailTasks);