Reputation: 89
I'm trying to send a mail message using System.Net.Mail.SmtpClient
with SSL enabled. While changing no external factors (i.e. hit F5, then hit F5 Again - or even in a loop) it works some times, but most of the times it fails.
Example code:
public void SendMail()
{
using (var client = new SmtpClient())
{
MailMessage mailMessage = new MailMessage();
client.EnableSsl = true;
client.Host = "smtp.example.com";
client.Timeout = 10000;
client.DeliveryMethod = SmtpDeliveryMethod.Network;
mailMessage.From = new MailAddress("[email protected]");
mailMessage.To.Add(new MailAddress("[email protected]"));
mailMessage.Subject = "Test";
mailMessage.Body = "Message " + DateTime.Now.ToString();
try
{
client.Send(mailMessage);
}
catch (Exception ex)
{
// This being a Pokemon block is besides the point
}
}
}
In my catch block I just get a timeout, but if I set up a trace for System.Net
and System.Net.Sockets
I can see a number of different exceptions:
- Unable to read data from the transport connection: A blocking operation was interrupted by a call to WSACancelBlockingCall
- Unable to read data from the transport connection: An established connection was aborted by the software in your host machine
- Cannot access a disposed object
- Reading is not supported on this stream
- Writing is not supported on this stream
All of which happen post EHLO, STARTTLS and authentication. The client and the server are chatting along in their cryptographic ways when the exceptions are thrown.
System.Net.Mail.SmtpClient.Send()
is the the only frame all call stacks have in common.
Of course I've tried changing the code in a number of ways, such as setting client.UseDefaultCredentials
, using client.SendAsync()
and whatnot. But I suspect it's something entirely different knocking the connection over at different times - a configuration error on one of the machines involved perhaps?
So I've checked the Event Logs for signs of something messing with the connection, but I haven't found anything.
Any suggestions as to what I should be looking for here?
Upvotes: 0
Views: 1755
Reputation: 89
Sometimes a timeout is just a timeout ...
Digging further into this issue I used Wireshark to see what was going on at the network level.
When the failures happened, the client machine invariably sent a TCP [RST, ACK] packet around 10 seconds after EHLO. A timespan conspicuously close to my timeout value. When I doubled the timeout value the mails came through without failure every single time.
Of course if we were to spend more than 10 seconds sending each mail, we'd soon be queuing up mails for hours in our production system, so I needed to find out why it took so long.
One detail caught my attention:
The client was spending upwards of four seconds between two packets. And it was generally spending hundreds of milliseconds between packets whereas the server would respond within tens.
The next step was to build the code without debug symbols and measure again without a debugger attached. The time spent per e-mail sent immediately went sub-second. Now it's no news to me that code runs slower with a debugger attached, but seeing it run that much slower was a surprise.
So the lessons for me to learn were: Try not to overanalyze, and when timing is involved kill the debugger once in a while.
Upvotes: 2
Reputation: 807
This should be a comment (I don't have reputation to make comments), but it could be a firewall issue, given you're getting an "Unable to read data from the transport connection: An established connection was aborted by the software in your host machine" error (basically, firewall or anti-virus cancelled your attempt to send a mail).
The error "Unable to read data from the transport connection: A blocking operation was interrupted by a call to WSACancelBlockingCall" happens when a stream is closed - see this question - and the other errors you've listed seem like they're related to trying to access a stream when it's closed, too.
All these error point to a common cause, a connection cancelled somewhere between you and the server and most likely on your machine/ network, and you get different errors depending at what point the effect propagates through to your application.
Another thing is, if you use
Credentials = new NetworkCredential(fromAddress.Address, fromPassword)
then you have to enable ssl afterwards, not before, otherwise it's cleared.
Upvotes: 1
Reputation: 333
I suppose you have missed to set Credentials
property of your host. However the another reason for exceptions may be wrong host name and port.Try something like :
public void SendMail()
{
try
{
var fromAddress = new MailAddress("[email protected]", "Some text");
var toAddress = new MailAddress("[email protected]");
const string fromPassword = "from account password";
var smtp = new SmtpClient
{
Host = "smtp.example.com",
Port = "your host port", //for gmail is 587
EnableSsl = true,
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false,
Credentials = new NetworkCredential(fromAddress.Address, fromPassword)
};
using (var message = new MailMessage(fromAddress, toAddress)
{
Subject = "Test",
Body = "Message " + DateTime.Now.ToString()
})
{
smtp.Send(message);
}
}
catch (Exception ex)
{
//do something
}
}
It is tested with gmail host which is smtp.gmail.com
and it works correctly
Upvotes: 0