【发布时间】:2018-03-06 03:59:08
【问题描述】:
我的代码发送这样的电子邮件:
private void DispatchMail(MailMessage mailMessage)
{
using (var smtpClient = new SmtpClient())
{
smtpClient.Send(mailMessage);
}
}
MailMessage 实例非常简单,只有 HTML 正文,没有附件。
SmtpClient 的配置在 web.config 中是这样的:
<system.net>
<mailSettings>
<smtp from="yourmail@gmail.com">
<network host="mailprovider.org" port="587" enableSsl="true" userName="username@host" password="secret" />
</smtp>
</mailSettings>
</system.net>
每当调用 DispatchMail 方法时,邮件实际上都会发送给收件人,但是我在隐式调用的 SmtpClient.Dispose 方法中遇到异常。
异常:无法从传输连接读取数据:现有连接被远程主机强行关闭。
在 System.Net.Sockets.NetworkStream.Read(Byte[] 缓冲区,Int32 偏移量,Int32 大小) 在 System.Net.FixedSizeReader.ReadPacket(字节 [] 缓冲区,Int32 偏移量,Int32 计数) 在 System.Net.Security._SslStream.StartFrameBody(Int32 readBytes,Byte[] 缓冲区,Int32 偏移量,Int32 计数,AsyncProtocolRequest asyncRequest) 在 System.Net.Security._SslStream.StartFrameHeader(字节 [] 缓冲区,Int32 偏移量,Int32 计数,AsyncProtocolRequest asyncRequest) 在 System.Net.Security._SslStream.StartReading(字节 [] 缓冲区,Int32 偏移量,Int32 计数,AsyncProtocolRequest asyncRequest) 在 System.Net.Security._SslStream.ProcessRead(字节 [] 缓冲区,Int32 偏移量,Int32 计数,AsyncProtocolRequest asyncRequest) 在 System.Net.TlsStream.Read(字节 [] 缓冲区,Int32 偏移量,Int32 大小) 在 System.Net.PooledStream.Read(字节 [] 缓冲区,Int32 偏移量,Int32 大小) 在 System.Net.Mail.SmtpPooledStream.Dispose(布尔处理) 在 System.IO.Stream.Close() 在 System.IO.Stream.Dispose() 在 System.Net.ConnectionPool.Destroy(PooledStream pooledStream) 在 System.Net.ConnectionPool.ForceCleanup() 在 System.Net.ConnectionPoolManager.CleanupConnectionPool(ServicePoint 服务点,字符串组名) 在 System.Net.Mail.SmtpClient.Dispose(布尔处理) 在 System.Net.Mail.SmtpClient.Dispose() 在 QueuedMailDispatcherService.DispatchMail(MailMessage mailMessage)
内部异常:现有连接被远程主机强行关闭
在 System.Net.Sockets.Socket.Receive(Byte[] 缓冲区,Int32 偏移量,Int32 大小,SocketFlags socketFlags) 在 System.Net.Sockets.NetworkStream.Read(Byte[] 缓冲区,Int32 偏移量,Int32 大小)
这是 .NET Framework 4.5.2 中的错误,还是我对 SMTP 客户端的生命周期管理不善?
有问题的 SMTP 服务器响应为“Microsoft ESMTP MAIL Service”。
更新
首先我忽略了这个问题,因为它只发生在我的机器上,但后来它发生在运行相同代码但具有发布配置的生产机器上。
由于此错误间歇性发生,我决定修改该方法以使用两级异常处理策略,其中忽略调用 Dispose 时发生的任何异常。
当我能够捕捉到这个错误并逐步执行框架源时,似乎偏移参数已损坏(它比 buffer.Length 高几 MB)在 System.Net.Sockets.NetworkStream.Read 和 System 之间的某个位置.Net.Sockets.Socket.Receive。然而,对源的进一步检查并不意味着偏移量会改变。实际上 System.Net.Security._SslStream.StartFrameHeader 在调用堆栈中将偏移量设置为 5 更高。这让我相信发生了以下其中一件事情:
- 调试后的机器级代码与我在 Visual Studio 中单步执行的源代码不匹配
- 某种内存损坏(但问题在一次重新启动以及在调试和发布配置的两台不同机器上仍然存在)
- 实际上我在调试两个不同的线程时并没有意识到
- 正在发生某种困难的罕见比赛条件
- 某种优化出了问题,可能与竞态条件有关
- 在 SMTP 退出期间 SMTP 服务器实现或网络传输不可靠,但它是一个众所周知的 SMTP 服务器软件,我不明白为什么这个问题会是间歇性的,也不能解释超出范围的偏移值。
【问题讨论】:
-
鉴于 Inerr Exception 状态
An existing connection was forcibly closed by the remote host表明这更有可能是连接到 SMTP 服务器的问题。我会仔细检查设置以确保它们正确。 -
您是否在使用 gmail 帐户?
-
我相信连接很好,连接已建立,消息已发送完毕。在处理对 Dispose 的调用时,似乎邮件服务器正在断开客户端的连接,但是据我所知,这应该是有效的。
-
看起来服务器违反了协议。当 .NET 发送 QUIT 命令时,它会死掉。服务器应该使用 221 响应来确认它。但相反,它立即终止了连接而不发送响应。建议向服务器所有者报告错误,同时您必须将 Dispose() 调用包装在 try/catch 中。
-
我在使用 Microsoft Office 365 时间歇性地遇到同样的错误。非常烦人...
标签: c# .net dispose smtpclient