c# - SmtpClient.Dispose 抛出 System.IO.IOException

标签 c# .net dispose smtpclient

我的代码发送这样的电子邮件:

    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 方法中遇到异常。

Exception: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.

at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size) at System.Net.FixedSizeReader.ReadPacket(Byte[] buffer, Int32 offset, Int32 count) at System.Net.Security._SslStream.StartFrameBody(Int32 readBytes, Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest) at System.Net.Security._SslStream.StartFrameHeader(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest) at System.Net.Security._SslStream.StartReading(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest) at System.Net.Security._SslStream.ProcessRead(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest) at System.Net.TlsStream.Read(Byte[] buffer, Int32 offset, Int32 size) at System.Net.PooledStream.Read(Byte[] buffer, Int32 offset, Int32 size) at System.Net.Mail.SmtpPooledStream.Dispose(Boolean disposing) at System.IO.Stream.Close() at System.IO.Stream.Dispose() at System.Net.ConnectionPool.Destroy(PooledStream pooledStream) at System.Net.ConnectionPool.ForceCleanup() at System.Net.ConnectionPoolManager.CleanupConnectionPool(ServicePoint servicePoint, String groupName) at System.Net.Mail.SmtpClient.Dispose(Boolean disposing) at System.Net.Mail.SmtpClient.Dispose() at QueuedMailDispatcherService.DispatchMail(MailMessage mailMessage)

Inner exception: An existing connection was forcibly closed by the remote host

at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags) at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)

这是 .NET Framework 4.5.2 中的错误还是我对 SMTP 客户端的生命周期管理不当?

有问题的 SMTP 服务器响应为“Microsoft ESMTP MAIL 服务”。

更新

首先我排除了这个问题,因为它只发生在我的机器上,但后来它发生在运行相同代码但具有发布配置的生产机器上。

由于此错误间歇性发生,我决定修改该方法以使用两级异常处理策略,在该策略中忽略调用 Dispose 时发生的任何异常。

当我能够捕捉到这个错误并单步执行框架源代码时,它似乎在 System.Net.Sockets.NetworkStream.Read 和 System 之间的某处损坏了偏移参数(它比缓冲区长度高几 MB) .Net.Sockets.Socket.Receive。然而,进一步检查来源并不意味着偏移量会改变。事实上,System.Net.Security._SslStream.StartFrameHeader 在调用堆栈中将偏移量设置为更高的 5。这让我相信发生了以下事情之一:

  • 调试的机器级代码与我在 Visual Studio 中单步执行的源代码不匹配
  • 某种内存损坏(但是通过一次重新启动以及在调试和发布配置中的两台不同机器上问题仍然存在)
  • 我实际上是在调试两个不同的线程而没有意识到这一点
  • 正在发生某种困难的罕见比赛情况
  • 存在某种优化错误,可能与竞争条件相结合
  • SMTP 服务器实现或网络传输在 SMTP 退出期间不可靠,但它是一个众所周知的 SMTP 服务器软件,我不明白为什么这个问题会间歇性发生,它也没有解释越界偏移值。

最佳答案

试试下面的例子:

using System.Net.Mail;


private void DispatchMail(string to)
{
    var mail = new MailMessage
    {
        Subject = "subject",
        From = new MailAddress(@"sender email", @"sender name")
    };
    mail.To.Add(to);
    mail.Body = "your message body";

    var smtp = new SmtpClient(@"smtp mail server address");
    smtp.Port = 587;
    smtp.Credentials = new System.Net.NetworkCredential("username", "password");
    smtp.EnableSsl = true;
    smtp.Send(mail);

    mail.Dispose();
    smtp.Dispose();
}

关于c# - SmtpClient.Dispose 抛出 System.IO.IOException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46400851/

相关文章:

C# - 我知道,我知道,关于 Dispose 的另一个问题(与设计更相关)!

c# - 仅写入一个 XML 属性,而不影响其余属性

c# - 为什么调度程序 BeginInvoke 在 C# Windows 窗体应用程序中 Control BeginInvoke 成功的地方失败?

c# - 防止在测量阶段调用 ApplyTemplate()

.net - 在JToken上进行Is操作编译

.net - F# 编译器使死对象保持事件状态

c# - 为什么 Bitmap 会导致规则 CA2000,而 Image 不会?

c# - 如何让 NUnit 测试等待线程完成?

c# - Winforms WPF 互操作性能

c# - 拥有一次性字段的类型应该是一次性的。如何解决这个警告?