SendAsyn c против SendMailAsyn c против новой темы против Parallel.ForEach за отправку 300-500 писем - PullRequest
0 голосов
/ 25 февраля 2020

TLDR; Что из следующего (или иного) наиболее подходит для быстрой отправки 300-500 писем на внешний почтовый сервер?

  1. SmtpClient.SendAsyn c
  2. SmtpClient.SendMailAsyn c
  3. новая тема
  4. Parallel.ForEach

Я изменяю код для отправки электронных писем, чтобы теперь использовать внешнего отправителя (например, MailGun, SendGrid et c.) Вместо HMailServer, который в настоящее время установлен на том же сервере, что и приложение. Это, очевидно, создает задержку.

Я прочитал документацию по всем вышеперечисленным, но изо всех сил пытаюсь полностью понять последствия (особенно gotcha's ) каждого. Кажется, существуют очень разные мнения о том, подходят ли вышеперечисленные подходы или нет, в частности:

  1. Если мне приходится ждать каждое электронное письмо, то разве это не имитирует текущий подход syn c?
  2. Я пытаюсь использовать один экземпляр объекта SmptClient для скорости и эффективности.
  3. Основываясь на сегодняшнем обширном чтении, многие примеры, которые я видел, старые и могут не использовать последние. Net Способности

Я бы приветствовал мнение людей, которые действительно достигли этого успеха. Естественно, я могу go написать код для каждого, но я ищу опытных людей, которые помогут мне выбрать правильный путь для начала здесь.

Мой упрощенный ( существующий син c) код выглядит следующим образом:

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);
        }
    }
}

1 Ответ

1 голос
/ 26 февраля 2020

Для задач ввода-вывода, таких как отправка электронной почты, вы не хотите использовать Parallel. Это удваивается, если вы работаете на ASP. NET. Кроме того, вы не хотите использовать new Thread, если не выполняете COM-взаимодействие.

Если вы хотите сделать его асинхронным, самый простой способ - оставить все как есть и просто вместо этого вызвать 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 больше не является общим)

Я не использовал SMTP API SendGrid в масштабе, но я столкнулся с их REST API со значительным количеством запросов.

...