SendAsync vs SendMailAsync vs new Thread vs Parallel.ForEach 用于发送 300-500 封电子邮件
SendAsync vs SendMailAsync vs new Thread vs Parallel.ForEach for sending 300-500 emails
TLDR;以下哪项(或其他)最适合向外部邮件服务器快速发送 300-500 封电子邮件?
我正在修改发送电子邮件的代码,现在使用外部发件人(例如 MailGun、SendGrid 等),而不是当前与应用程序安装在同一服务器上的 HMailServer。这显然引入了延迟。
我已经阅读了上述所有内容的文档,但我很难完全理解每个内容的含义(尤其是 陷阱)。关于以上是否合适,似乎有很大的不同意见,特别是:
- 如果我必须等待每封邮件,那不是在模拟当前的同步方式吗?
- 我正在尝试使用 SmptClient 对象的单个实例,以提高速度和效率
- 根据今天的广泛阅读,我看到的许多示例都是旧的,可能没有使用最新的 .Net 功能
我欢迎实际成功实现这一目标的人提供意见。当然,我可以为每个代码编写代码,但我正在寻找有经验的人来指导我走上正确的道路。
我的简化(现有同步)代码如下:
var sb = new StringBuilder();
using (var mc = new SmtpClient() {
Host = "127.0.0.1", // Current HMailServer installation - will be changed to external API
DeliveryMethod = SmtpDeliveryMethod.Network,
Port = 25,
UseDefaultCredentials = false,
Credentials = new NetworkCredential("Username", "Password")
})
{
foreach(var result in GetData())
{
using(var mm = new MailMessage())
{
mm.To.Add(new MailAddress(result.Email, result.FirstName + " " + result.Surname));
mm.Subject = "Your monthly report";
mm.From = new MailAddress("noreply@example.com");
mm.ReplyToList.Add(new MailAddress(result.Email));
// Email body constructed here for each individual recipient
mm.Body = sb.ToString();
sb.Clear();
mc.Send(mm);
}
}
}
对于发送电子邮件等 I/O-bound 任务,您 不想 使用 Parallel
。如果您在 ASP.NET 上 运行,这将翻倍。此外,除非您正在进行 COM 互操作,否则您不想使用 new Thread
。
如果你想让它异步,最简单的方法是保持一切不变,只调用 SendAsync
而不是 Send
:
var sb = new StringBuilder();
using (var mc = new SmtpClient() {
Host = "127.0.0.1", // Current HMailServer installation - will be changed to external API
DeliveryMethod = SmtpDeliveryMethod.Network,
Port = 25,
UseDefaultCredentials = false,
Credentials = new NetworkCredential("Username", "Password")
})
{
foreach(var result in GetData())
{
using(var mm = new MailMessage())
{
mm.To.Add(new MailAddress(result.Email, result.FirstName + " " + result.Surname));
mm.Subject = "Your monthly report";
mm.From = new MailAddress("noreply@example.com");
mm.ReplyToList.Add(new MailAddress("admin@example.com"));
// Email body constructed here for each individual recipient
mm.Body = sb.ToString();
sb.Clear();
await mc.SendAsync(mm);
}
}
}
现在,如果您想同时执行此操作,则需要使用Task.WhenAll
:
using (var mc = new SmtpClient() {
Host = "127.0.0.1", // Current HMailServer installation - will be changed to external API
DeliveryMethod = SmtpDeliveryMethod.Network,
Port = 25,
UseDefaultCredentials = false,
Credentials = new NetworkCredential("Username", "Password")
})
{
var tasks = GetData().Select(async result =>
{
using(var mm = new MailMessage())
{
mm.To.Add(new MailAddress(result.Email, result.FirstName + " " + result.Surname));
mm.Subject = "Your monthly report";
mm.From = new MailAddress("noreply@example.com");
mm.ReplyToList.Add(new MailAddress("admin@example.com"));
var sb = new StringBuilder();
// Email body constructed here for each individual recipient
mm.Body = sb.ToString();
await mc.SendAsync(mm);
}
});
await Task.WhenAll(tasks);
}
(注意 StringBuilder
不再共享)
我还没有大规模使用 SendGrid SMTP API,但我已经用相当多的请求访问了他们的 REST API。
TLDR;以下哪项(或其他)最适合向外部邮件服务器快速发送 300-500 封电子邮件?
我正在修改发送电子邮件的代码,现在使用外部发件人(例如 MailGun、SendGrid 等),而不是当前与应用程序安装在同一服务器上的 HMailServer。这显然引入了延迟。
我已经阅读了上述所有内容的文档,但我很难完全理解每个内容的含义(尤其是 陷阱)。关于以上是否合适,似乎有很大的不同意见,特别是:
- 如果我必须等待每封邮件,那不是在模拟当前的同步方式吗?
- 我正在尝试使用 SmptClient 对象的单个实例,以提高速度和效率
- 根据今天的广泛阅读,我看到的许多示例都是旧的,可能没有使用最新的 .Net 功能
我欢迎实际成功实现这一目标的人提供意见。当然,我可以为每个代码编写代码,但我正在寻找有经验的人来指导我走上正确的道路。
我的简化(现有同步)代码如下:
var sb = new StringBuilder();
using (var mc = new SmtpClient() {
Host = "127.0.0.1", // Current HMailServer installation - will be changed to external API
DeliveryMethod = SmtpDeliveryMethod.Network,
Port = 25,
UseDefaultCredentials = false,
Credentials = new NetworkCredential("Username", "Password")
})
{
foreach(var result in GetData())
{
using(var mm = new MailMessage())
{
mm.To.Add(new MailAddress(result.Email, result.FirstName + " " + result.Surname));
mm.Subject = "Your monthly report";
mm.From = new MailAddress("noreply@example.com");
mm.ReplyToList.Add(new MailAddress(result.Email));
// Email body constructed here for each individual recipient
mm.Body = sb.ToString();
sb.Clear();
mc.Send(mm);
}
}
}
对于发送电子邮件等 I/O-bound 任务,您 不想 使用 Parallel
。如果您在 ASP.NET 上 运行,这将翻倍。此外,除非您正在进行 COM 互操作,否则您不想使用 new Thread
。
如果你想让它异步,最简单的方法是保持一切不变,只调用 SendAsync
而不是 Send
:
var sb = new StringBuilder();
using (var mc = new SmtpClient() {
Host = "127.0.0.1", // Current HMailServer installation - will be changed to external API
DeliveryMethod = SmtpDeliveryMethod.Network,
Port = 25,
UseDefaultCredentials = false,
Credentials = new NetworkCredential("Username", "Password")
})
{
foreach(var result in GetData())
{
using(var mm = new MailMessage())
{
mm.To.Add(new MailAddress(result.Email, result.FirstName + " " + result.Surname));
mm.Subject = "Your monthly report";
mm.From = new MailAddress("noreply@example.com");
mm.ReplyToList.Add(new MailAddress("admin@example.com"));
// Email body constructed here for each individual recipient
mm.Body = sb.ToString();
sb.Clear();
await mc.SendAsync(mm);
}
}
}
现在,如果您想同时执行此操作,则需要使用Task.WhenAll
:
using (var mc = new SmtpClient() {
Host = "127.0.0.1", // Current HMailServer installation - will be changed to external API
DeliveryMethod = SmtpDeliveryMethod.Network,
Port = 25,
UseDefaultCredentials = false,
Credentials = new NetworkCredential("Username", "Password")
})
{
var tasks = GetData().Select(async result =>
{
using(var mm = new MailMessage())
{
mm.To.Add(new MailAddress(result.Email, result.FirstName + " " + result.Surname));
mm.Subject = "Your monthly report";
mm.From = new MailAddress("noreply@example.com");
mm.ReplyToList.Add(new MailAddress("admin@example.com"));
var sb = new StringBuilder();
// Email body constructed here for each individual recipient
mm.Body = sb.ToString();
await mc.SendAsync(mm);
}
});
await Task.WhenAll(tasks);
}
(注意 StringBuilder
不再共享)
我还没有大规模使用 SendGrid SMTP API,但我已经用相当多的请求访问了他们的 REST API。