C# 为什么SmtpClient在使用SSL时会出现几个不同的异常而失败?
我正在尝试使用启用SSL的C# 为什么SmtpClient在使用SSL时会出现几个不同的异常而失败?,c#,ssl,smtp,system.net.mail,system.net,C#,Ssl,Smtp,System.net.mail,System.net,我正在尝试使用启用SSL的System.Net.mail.SmtpClient发送邮件消息。虽然没有改变任何外部因素(即,点击F5,然后再次点击F5,甚至在循环中),但它有时会工作,但大多数情况下会失败 示例代码: public void SendMail() { using (var client = new SmtpClient()) { MailMessage mailMessage = new
System.Net.mail.SmtpClient
发送邮件消息。虽然没有改变任何外部因素(即,点击F5,然后再次点击F5,甚至在循环中),但它有时会工作,但大多数情况下会失败
示例代码:
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("from@example.com");
mailMessage.To.Add(new MailAddress("to@example.com"));
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
}
}
}
在catch块中,我只得到一个超时,但是如果我为System.Net
和System.Net.Sockets
设置跟踪,我可以看到许多不同的异常:
- 无法从传输连接读取数据:对WSACancelBlockingCall的调用中断了阻塞操作
- 无法从传输连接读取数据:主机中的软件中止了已建立的连接
- 无法访问已释放的对象
- 此流不支持读取
- 此流不支持写入
System.Net.Mail.SmtpClient.Send()
是所有调用堆栈的唯一共同框架
当然,我尝试过用多种方式更改代码,例如设置client.UseDefaultCredentials
,使用client.SendAsync()
等等。但我怀疑在不同的时间中断连接是完全不同的——可能是其中一台机器上的配置错误
因此,我检查了事件日志,查看是否有迹象表明连接有问题,但我没有发现任何东西
关于我应该在这里寻找什么,有什么建议吗?我想您没有设置主机的
凭据。但是,出现异常的另一个原因可能是主机名和端口错误。请尝试以下操作:
public void SendMail()
{
try
{
var fromAddress = new MailAddress("from@example.com", "Some text");
var toAddress = new MailAddress("to@example.com");
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
}
}
它是用gmail主机测试的,它是smtp.gmail.com
,工作正常我想你没有设置主机的凭证
属性。但是,出现异常的另一个原因可能是主机名和端口错误。请尝试以下操作:
public void SendMail()
{
try
{
var fromAddress = new MailAddress("from@example.com", "Some text");
var toAddress = new MailAddress("to@example.com");
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
}
}
这是用gmail主机测试的,它是smtp.gmail.com
,工作正常这应该是一个评论(我没有发表评论的名声),但如果你得到一个“无法从传输连接读取数据:已建立的连接被主机中的软件中止”错误(基本上,防火墙或防病毒软件取消了您发送邮件的尝试)
“无法从传输连接读取数据:对WSACancelBlockingCall的调用中断了阻塞操作”错误发生在流关闭时—请参阅—您列出的其他错误似乎也与在流关闭时尝试访问流有关
所有这些错误都指向一个共同的原因,即在您和服务器之间的某个地方以及最有可能在您的计算机/网络上取消的连接,并且您会收到不同的错误,这取决于影响传播到应用程序的点
另一件事是,如果你使用
Credentials=新网络凭据(fromAddress.Address,fromPassword)
然后您必须在之后而不是之前启用ssl,否则它将被清除。这应该是一个注释(我没有发表评论的声誉),但这可能是一个防火墙问题,因为您会遇到“无法从传输连接读取数据:已建立的连接被主机中的软件中止”错误(基本上,防火墙或防病毒软件会取消您发送邮件的尝试)
“无法从传输连接读取数据:对WSACancelBlockingCall的调用中断了阻塞操作”错误发生在流关闭时—请参阅—您列出的其他错误似乎也与在流关闭时尝试访问流有关
所有这些错误都指向一个共同的原因,即在您和服务器之间的某个地方以及最有可能在您的计算机/网络上取消的连接,并且您会收到不同的错误,这取决于影响传播到应用程序的点
另一件事是,如果你使用
Credentials=新网络凭据(fromAddress.Address,fromPassword)
然后您必须在之后而不是之前启用ssl,否则它将被清除。有时超时只是一个超时
我使用Wireshark进一步研究了这个问题,以了解网络层面的情况
当发生故障时,客户机总是在EHLO后10秒左右发送TCP[RST,ACK]数据包。时间跨度明显接近我的超时值。当我将超时值加倍时,邮件每次都能顺利通过
当然,如果我们发送每封邮件的时间超过10秒,我们很快就会在生产系统中将邮件排队数小时,所以我需要找出为什么要花这么长时间
一个细节引起了我的注意:
客户端在两个数据包之间花费了超过4秒的时间,并且通常在两个数据包之间花费了数百毫秒,而服务器会在数十秒内做出响应
下一步是在没有调试符号的情况下构建代码,并在没有附加调试程序的情况下再次测量。每发送一封电子邮件所花费的时间立即达到了亚秒。现在,对于我来说,附加调试程序的代码运行速度变慢已经不是什么新鲜事了,但看到它运行速度如此之慢真是令人惊讶
因此,我要吸取的教训是:尽量不要过度分析,当涉及计时时,偶尔杀死调试器。有时超时就是超时
我使用Wireshark进一步研究了这个问题,以了解网络层面的情况
当发生故障时,客户机总是发送一个