【问题标题】:Sending 500 email messages using ASP.NET MVC: throttling使用 ASP.NET MVC 发送 500 封电子邮件:节流
【发布时间】:2015-02-17 10:03:18
【问题描述】:

我正在尝试从 ASP.NET MVC 4 Web 应用程序向我们的客户发送 500 封电子邮件。我只是使用如下所示的 foreach 循环。大约 50 个周期后,我得到一个通用异常,说无法发送邮件消息。我相信我正在处理限制我的 Web 应用程序的 节流MS Exchange 设置。如何简单地实施限制以绕过这些限制?

谢谢。

foreach (var toAddress in addresses)
{
   var message = new MailMessage(fromAddress, toAddress)
   {
      Subject = subject,
      Body = body
   };

   message.IsBodyHtml = isHtml;

   try
   {
      using (var client = new SmtpClient())
      {
         client.Send(message);
      }
   }
   catch (Exception ex)
   {
      Debug.WriteLine("Cannot send e-mail to " + message.To + Environment.NewLine +
                      "Subject: " + subject + Environment.NewLine +
                      "Body: " + body + Environment.NewLine + 
                      "Exception: " + ex.Message);
   }
}

【问题讨论】:

  • 一个问题可能是为每封电子邮件打开/关闭 SmtpClient。您是否尝试过只打开一次连接并在 foreach 循环后关闭?
  • 恕我直言,认真思考,并注意下面 Brad 的 cmets。这在某些方面超出了技术问题,这就是为什么在现实世界的业务中,此类任务通常由适当的服务/提供商(例如营销/群发电子邮件提供商)完成,而不是在内部完成。嗯……
  • 由于所有邮件都具有相同的正文和主题,您可以使用密件抄送将每封电子邮件发送给多个客户,而不是向每个客户发送单独的邮件。生成的电子邮件不会显示收件人地址,但您可以有效地将其快速发送到您的电子邮件服务器。
  • @Grax:这不是我的情况,抱歉。每条消息都有不同的正文。

标签: c# asp.net asp.net-mvc email exchange-server


【解决方案1】:

我会查看Quartz.NET 并使用服务发送电子邮件。至于排队,也许可以研究一下简单的文件存储或数据库。

如果您使用Thread.Sleep 之类的东西,请记住您将阻止服务器呈现最终输出(例如,如果这是通过表单提交触发的,则在所有电子邮件都完成之前不会显示结果视图发送)。通过使用像quartz 这样的库,您可以在减轻电子邮件发送负担的同时保持服务器对请求的响应。

另外,作为参考,还有另一篇关于在不拖动 UX 的情况下执行昂贵操作的 SO 帖子。这可以在here 找到,(恕我直言)TheCodeKing 的最相关答案。

【讨论】:

  • 保持渲染不会有问题。问题是现在即使使用Thread.Sleep(1000) 我也可以发送所有这些...
  • 我的意思是我不能让他们在每次发送之间等待 1000 毫秒,我现在正在尝试 5000 毫秒...
  • 在你开始猜测之前,我要么上网,要么打电话给电子邮件提供商,看看你可以在一小时内发送多少封邮件。两个原因:您会知道要使用什么延迟,并且您还想知道,因为在您发送 500 封电子邮件后,您可能无法发送正常的电子邮件(如果这是一项业务,我怀疑公司会快乐)。
  • 现在我还有一个疑问,如果@domain.com 不再存在,我是否有可能得到以下异常? A first chance exception of type 'System.Net.Mail.SmtpException' occurred in System.dll.我看到在一些错误之后它能够继续发送......
  • 异常信息是什么?
【解决方案2】:

如果您使用 Exchange 2010 或更高版本,则有一个 RecipientRateLimit 限制策略参数,用于指定用户在 24 小时内可以处理的收件人数量限制。如果您想绕过此限制,您需要更改发送这些消息的用户的限制策略,请参阅http://www.slipstick.com/exchange/limit-number-of-internet-messages-user-can-send/

干杯 格伦

【讨论】:

  • 你能帮我解决这个语法Set-Mailbox -Identity user_alias -ThrottlingPolicy LimitMessagesSent吗?我的帐户名称是 noreply@domain.com,我想知道在更改之前有什么限制...
  • 要获取与用户相关联的限制策略,请使用 Get-ThrottlingPolicyAssociation user@domain | format-list 这将告诉您是应用了默认策略(例如,空白 policyId)还是应用了自定义策略。您通常会期望已应用默认策略。您需要做的是创建一个具有所需设置的新策略,然后将其应用于您的用户,例如 blogs.technet.com/b/samdrey/archive/2013/03/27/…
【解决方案3】:

我们的场景是使用本地 MS Exchange Server 2010 的远程 Web 应用程序,目前唯一可行的解​​决方案如下。每 10 秒使用 20 到 30 条消息块,我可以向我们的客户发送我想要的自定义电子邮件数量,而无需触及 MS Exchange Sever 2010 配置(这需要数小时的培训)。此外,所有内容都记录在 TXT 文件中,以确保消息已实际发送。我还推荐使用 MS Exchange Tracking Log Explorer 工具来检查是否发送了消息以及发送了哪些消息。

private void SendBulkEmail(List<KeyValuePair<Customer, Order>> customerList, MailAddress sender, string subject, string body, bool isHtml, string fileNamePrefix)
{
    const int chunkSize = 20;

    string rootPath = Server.MapPath("~");

    string path = Path.GetFullPath(Path.Combine(rootPath, "Logs"));

    string fileName = CommonUtils.GetLogFileName(path, fileNamePrefix);

    int len = customerList.Count;

    TextWriter tw = new StreamWriter(fileName);

    int chunkCount = (len / chunkSize) + 1;
    int remainder = len % chunkSize;

    for (int j = 0; j < chunkCount; j++)
    {
       int start = j * chunkSize;
       int end = start + chunkSize;

       if (j == chunkCount - 1)
       {
           end = start + remainder;
       }

       SmtpClient client = new SmtpClient();

       for (int i = start; i < end; i++)
       {
           Customer customer = customerList[i].Key;

           Guid userGuid = new Guid(customer.UserId.ToString());
           MembershipUser membershipUser = Membership.GetUser(userGuid);

           string memberUsername = membershipUser.UserName;
           string memberEmail = membershipUser.Email;

           SendMessage(sender, recipient, subject, body, tw, client, context);

       }

       client.Dispose();

       Thread.Sleep(10000); // 10 seconds

       tw.WriteLine("Completed chunk #" + j);
   }

   tw.Close();
 }

public static void SendEmail(MailAddress fromAddress, MailAddress toAddress, string subject, string body, TextWriter tw, SmtpClient smtpClient)
{
    MailMessage message = new MailMessage(fromAddress, toAddress)
    {
       Subject = subject,
       Body = body
    };

    try
    {
       smtpClient.Send(message);

       if (tw != null)
       {
          tw.WriteLine("\"" + toAddress + "\",");
       }
    }
    catch (Exception ex)
    {
       if (tw != null)
       {
          tw.WriteLine(toAddress + ": " + ex.Message + " " + ex.InnerException.Message);
       }

       Debug.WriteLine("Cannot send e-mail to " + toAddress + ", " + "Exception: " + ex.Message + (ex.InnerException != null ? ", " + ex.InnerException.Message : string.Empty));
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-11
    • 1970-01-01
    相关资源
    最近更新 更多