使用实体框架并发送最多500封电子邮件时,Windows服务中的C#超时

时间:2016-06-14 15:23:42

标签: c# entity-framework windows-services

我有一个每5分钟运行一次的Windows服务来发送电子邮件。一次性发送最多可能发送500封电子邮件。就在最近我们转移到Gmail发送电子邮件,这导致服务重复(每小时几次)投下以下消息:

"操作完成前经过的超时时间或服务器没有响应"

在后台有一个计时器,每5分钟就会发送一次,以发送所有堆积的电子邮件。触发后,它会停止计时器,使用Entity Framework 6获取电子邮件,循环并发送所有这些电子邮件,最后再次启动计时器。

private void FetchAndSendEmails(object sender, ElapsedEventArgs elapsedEventArgs)
{
    _serverTimer.Stop();

    try 
    {
        var db = new MainServerContext();
        var emailsToSend = db.Mails
                           .Where(x => x.IsSent.Equals(false) && x.IsDeleted.Equals(false))
                           .OrderBy(x => x.Priority)
                           .ThenBy(x => x.EntryCreated)
                           .Take(_maxEmailsToSendPerExecution)
                           .Select(x => new MailItem() { Id = x.MailId, Recipient = x.Recipient }) }).ToList(); // Fetches a lot more fields here

        for (int i = 0; i < emailsToSend.Count(); i++)
        {
            var dbEmail = emailsToSend[i];
            SendEmail(0, dbEmail, ref db);
            continue;
        }
    }
    catch (Exception ex)
    {
        // Log error                
    }
    finally
    {
        _serverTimer.Start();
    }
}

SendEmail方法

var mailClient = new SmtpClient();            
mailClient.UseDefaultCredentials = true;
mailClient.Host = _host; // smtp.gmail.com
mailClient.Port = _port; // 465
mailClient.EnableSsl = _useSSL;
mailClient.DeliveryMethod = SmtpDeliveryMethod.Network;
mailClient.Credentials = new NetworkCredential(mailerItem.Username, mailerItem.Password);
mailClient.Timeout = 20000;

//add recipient, body, attachments etc.

mailClient.Send(message);

// Update mail sent
var item = db.Mails.First(x => x.MailId.Equals(mail.Id));
item.IsSent = true;
item.Sent = DateTime.Now;
item.FromEmail = mailerItem.FromEmailAddress;
db.SubmitChanges();

我可能会过去使用异步吗?以不同方式声明EF?更改一些Gmail设置?

有什么想法吗?

2 个答案:

答案 0 :(得分:0)

我遇到了与Gmail相同的问题,他们的邮件服务器在哪些应用程序发送电子邮件方面受到很大保护。另外,请确保您没有该帐户的两步验证。

我切换到SMTP2Go(smtp2go.com),我可以发送尽可能多的电子邮件。

以下是我用来发送大量电子邮件的代码片段:http://pastie.org/10876521

答案 1 :(得分:0)

确保代码等待FetchAndSendEmails()完成,即使花费的时间超过5分钟。

一次加载和处理1封电子邮件,而不是500批次。

使用后处理DbContext。

  using (var db = new MainServerContext())
  {
     ...
  }

可能会卡在一封电子邮件中。记录每封电子邮件的尝试次数,并轮流发送。

确保在调用FetchAndSendEmails()时没有TransactionScope有效,因为事务的硬编码最大时间限制为10分钟 - 并且没有实际的方法来扩展该限制(事务是假设的)是短暂的)。如果超出该限制,您将获得例外。