Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Email sending service in c# doesn't recover after server timeout

I've been having this problem for months, and it's driving me nuts. I have a windows service written in C# (.NET 4.5) which basically sends emails, using an outlook account (I think it's an office365 service). I'm aware of the "order of credentials" problem, which isn't affecting me (many emails send correctly).

The service starts correctly and begins sending emails. Sometimes when there's too many, I get a server error to wait, the service waits a few minutes and continues perfectly on its own.

In these cases I get Error A:

 System.Net.Mail.SmtpException: The operation has timed out.
   at System.Net.Mail.SmtpClient.Send(MailMessage message)
   at Cobranzas.WinService.Email.SendEmail(String subject, String body, String mailTo, String attPath)
   at Cobranzas.WinService.CobranzasEmailService.SendEmails(IEnumerable`1 toSend, RepositoryEf emailRepo)

The problem: sometimes, and I haven't been able to find a pattern, it happens every few days, it gets a timeout error, and never recovers (restarting the services fixes it immediately). All subsequent sending tries fail with the same error. In this case, I get a mix of Error A and:

 System.Net.Mail.SmtpException: Failure sending mail. ---> System.Net.WebException: The operation has timed out.
   at System.Net.ConnectionPool.Get(Object owningObject, Int32 result, Boolean& continueLoop, WaitHandle[]& waitHandles)
   at System.Net.ConnectionPool.GetConnection(Object owningObject, GeneralAsyncDelegate asyncCallback, Int32 creationTimeout)
   at System.Net.Mail.SmtpConnection.GetConnection(ServicePoint servicePoint)
   at System.Net.Mail.SmtpTransport.GetConnection(ServicePoint servicePoint)
   at System.Net.Mail.SmtpClient.GetConnection()
   at System.Net.Mail.SmtpClient.Send(MailMessage message)
   --- End of inner exception stack trace ---
   at System.Net.Mail.SmtpClient.Send(MailMessage message)
   at Cobranzas.WinService.Email.SendEmail(String subject, String body, String mailTo, String attPath)
   at Cobranzas.WinService.CobranzasEmailService.SendEmails(IEnumerable`1 toSend, RepositoryEf emailRepo)

The logic of my service is as follows: I have a timer which every 5 minutes iterates over a lot of emails to be sent, and for each executes

Thread.Sleep(2000); 
try
{
    emailService.SendEmail(asunto, nuevoCuerpo, mail.Email, mail.AlertMessage.Attach);
}
catch (Exception ex)
{
    if (ex is System.Net.Mail.SmtpException)
    {
        Thread.Sleep(20000); // Lo hacemos esperar 20 segundos
    }
}

SendEmail method is:

var mailMessage = new MailMessage();

mailMessage.To.Add(mailTo);

mailMessage.Subject = subject;
mailMessage.Body = WebUtility.HtmlDecode(body);
mailMessage.IsBodyHtml = true;
mailMessage.From = new MailAddress(emailFromAddress, emailFromName); 
mailMessage.Headers.Add("Content-type", "text/html; charset=iso-8859-1");

// Attachment
if (attPath != null)
{
    var data = new Attachment(attPath, MediaTypeNames.Application.Octet);
    mailMessage.Attachments.Add(data);
}

var cred =
    new NetworkCredential(emailFromAddress, emailFromPassword); 

using (var mailClient =
    new SmtpClient(emailSmtpClient, emailSmtpPort) 
                     {
                         EnableSsl = true,
                         DeliveryMethod = SmtpDeliveryMethod.Network,
                         UseDefaultCredentials = false,
                         Timeout = 20000,
                         Credentials = cred
                     })
{
    mailClient.Send(mailMessage);
}

foreach (Attachment attachment in mailMessage.Attachments)
{
    attachment.Dispose();
}

The using SmtpClient, and attachment disposing are new, we added them trying to fix this. There was no behaviour change. T̶h̶e̶ ̶T̶h̶r̶e̶a̶d̶.̶S̶l̶e̶e̶p̶ ̶a̶f̶t̶e̶r̶ ̶t̶h̶e̶ ̶t̶i̶m̶e̶o̶u̶t̶ ̶i̶s̶ ̶n̶e̶w̶ ̶a̶n̶d̶ ̶u̶n̶t̶e̶s̶t̶e̶d̶ ̶y̶e̶t̶.

Given that restarting the service fixes it, I'm suspecting something not being closed/cleaned appropriately, but I've checked and can't find what it could be. I found this link a while ago, but it looks pretty old.

Any help is much appreciated!

[PROGRESS]

I've tested the 20" wait after a timeout and nothing, it's still failing in the same way. Any ideas? We're really stumped with this.

like image 506
shinax Avatar asked Jul 08 '14 13:07

shinax


1 Answers

I have the exact same problem. I found the solution here:

System.Net.WebException when issuing more than two concurrent WebRequests http://www.wadewegner.com/2007/08/systemnetwebexception-when-issuing-more-than-two-concurrent-webrequests/

Basically, I changed the max number of connections allowed concurrently to a single external server. By default, according to that documentation it was 2. Although, it has a timeout (it waits sometime until one is released and then continues), at sometimes, it is not enough and it hangs.

<configuration>
    <system.net>
        <connectionManagement>
        <add address="*" maxconnection="100" />
        </connectionManagement>
    </system.net>
</configuration>

I have not been able to find out how to recover after first timeout but hopefully this would get out "timeout" errors out of the way for some time.

like image 106
user3691460 Avatar answered Oct 11 '22 14:10

user3691460