【问题标题】:SmtpException: Unable to read data from the transport connection: net_io_connectionclosedSmtpException:无法从传输连接中读取数据:net_io_connectionclosed
【发布时间】:2013-12-12 06:41:32
【问题描述】:

我正在使用SmtpClient 库通过以下方式发送电子邮件:

SmtpClient client = new SmtpClient();
client.Host = "hostname";
client.Port = 465;
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = false;
client.EnableSsl = true;
client.Credentials = new NetworkCredential("User", "Pass);
client.Send("from@hostname", "to@hostname", "Subject", "Body");

代码在我的测试环境中运行良好,但是当我使用生产 SMTP 服务器时,代码失败并显示SmtpException“发送邮件失败”。带有内部IOException“无法从传输连接读取数据:net_io_connectionclosed”。

我已经确认防火墙不是问题。端口在客户端和服务器之间打开得很好。我不确定还有什么可能引发此错误。

【问题讨论】:

    标签: c# smtp


    【解决方案1】:

    编辑:超级 Redux 版本

    尝试使用端口 587 而不是 465。端口 465 在技术上已被弃用。


    经过一堆数据包嗅探后,我想通了。首先,这是一个简短的答案:

    .NET SmtpClient仅支持通过 STARTTLS 进行加密。如果设置了EnableSsl 标志,则服务器必须使用 STARTTLS 响应 EHLO,否则将抛出异常。有关详细信息,请参阅MSDN 文档。

    其次,为将来偶然发现此问题的人提供的快速 SMTP 历史课程:

    过去,当服务还想提供加密时,它们被分配了一个不同的端口号,并在该端口号上立即启动 SSL 连接。随着时间的推移,他们意识到为一个服务浪费两个端口号是愚蠢的,他们设计了一种服务方法,允许使用 STARTTLS 在同一个端口上进行明文和加密。通信将使用明文开始,然后使用 STARTTLS 命令升级到加密连接。 STARTTLS 成为 SMTP 加密的标准。不幸的是,在实施新标准时总是会发生这种情况,因此与那里的所有客户端和服务器的兼容性都是大杂烩。

    在我的例子中,我的用户试图将软件连接到强制立即 SSL 连接的服务器,这是 Microsoft 在 .NET 中不支持的旧方法。

    【讨论】:

    • 如何判断我连接的服务器是否有同样的问题?我正在尝试将 SmtpClient 与 yahoo 和/或 gmail 一起使用并得到描述的错误。当我尝试使用 2013 交换服务器时,我的代码运行良好。
    • 最简单的测试方法是尝试使用端口 587 而不是 465。虽然一些 SMTP 服务器支持 465(有时甚至是 25)上的 TLS,但只需要端口 587 即可支持 TLS。除此之外,自 1998 年以来 (en.wikipedia.org/wiki/SMTPS) 已弃用端口 465,尽管实际上许多服务器已为旧版客户端启用它。
    • 是的,改成 587 就行了。感谢您为我指明正确的方向。
    • 587 有效,尽管 smtp.att.yahaoo.com 说使用 465。谢谢伙计。
    • 对于一个实际的解决方案,请参阅stackoverflow.com/a/1014876/247702 使用(已弃用)支持隐式 SSL 的 System.Web.Mail。
    【解决方案2】:

    对于偶然发现这篇文章并寻找解决方案并且您已通过 Azure 设置 SMTP sendgrid 的任何人。

    用户名不是您在 Azure 中创建 sendgrid 对象时设置的用户名。查找您的用户名;

    • 在 azure 中单击您的 sendgrid 对象,然后单击管理。您将被重定向到 SendGrid 站点。
    • 确认您的电子邮件,然后复制那里显示的用户名。这是一个自动生成的用户名。
    • 将 SendGrid 中的用户名添加到 web.config 文件中的 SMTP 设置中。

    希望这会有所帮助!

    【讨论】:

    • 这可能看起来很愚蠢,但您可能要检查的其他内容是密码是否适用于 SMTP SendGrid 设置。我们的设置最初是有效的,然后有一天我们开始收到 OP 的异常消息。在 WWW 上的搜索大多指向查看其他 SMTP 服务器配置,但最终发现密码不正确。团队中有人将配置文件中的密码更改为首字母不大写的变体。
    • 在我的情况下,用户名不正确并且有错字。但是错误的密码也会给出“无法从传输连接读取数据:net_io_connectionclosed”。错误。所以检查用户名和密码。对于 Azure 用户,用户名的格式为“azure_guid-withoutdashes@azure.com”(例如:azure_e9e062db4bfd491296bec77bcff49ed9@azure.com)
    【解决方案3】:

    将端口从 465 更改为 587 即可。

    【讨论】:

    • 我不确定发生了什么,但这对我使用 gmail smtp 有效。你能解释一下为什么会这样吗?
    【解决方案4】:

    我已尝试上述所有答案,但 Office 365 帐户仍然出现此错误。当允许不太安全的应用程序时,该代码似乎可以与 Google 帐户和 smtp.gmail.com 一起正常工作。

    我可以尝试任何其他建议吗?

    这是我正在使用的代码

    int port = 587;
    string host = "smtp.office365.com";
    string username = "smtp.out@mail.com";
    string password = "password";
    string mailFrom = "noreply@mail.com";
    string mailTo = "to@mail.com";
    string mailTitle = "Testtitle";
    string mailMessage = "Testmessage";
    
    using (SmtpClient client = new SmtpClient())
    {
        MailAddress from = new MailAddress(mailFrom);
        MailMessage message = new MailMessage
        {
            From = from
        };
        message.To.Add(mailTo);
        message.Subject = mailTitle;
        message.Body = mailMessage;
        message.IsBodyHtml = true;
        client.DeliveryMethod = SmtpDeliveryMethod.Network;
        client.UseDefaultCredentials = false;
        client.Host = host;
        client.Port = port;
        client.EnableSsl = true;
        client.Credentials = new NetworkCredential
        {
            UserName = username,
            Password = password
        }; 
        client.Send(message);
    }
    

    更新以及我是如何解决的:

    通过将 Smtp Client 更改为 Mailkit 解决了问题。由于安全问题,Microsoft 现在不建议使用 System.Net.Mail Smtp 客户端,您应该改用 MailKit。使用 Mailkit 给了我更清晰的错误消息,我可以理解找到问题的根本原因(许可证问题)。您可以通过将 Mailkit 下载为 Nuget 包来获取它。

    阅读有关 SMTP 客户端的文档以获取更多信息: https://docs.microsoft.com/es-es/dotnet/api/system.net.mail.smtpclient?redirectedfrom=MSDN&view=netframework-4.7.2

    这是我使用 MailKit 实现 SmtpClient 的方法

            int port = 587;
            string host = "smtp.office365.com";
            string username = "smtp.out@mail.com";
            string password = "password";
            string mailFrom = "noreply@mail.com";
            string mailTo = "mailto@mail.com";
            string mailTitle = "Testtitle";
            string mailMessage = "Testmessage";
    
            var message = new MimeMessage();
            message.From.Add(new MailboxAddress(mailFrom));
            message.To.Add(new MailboxAddress(mailTo));
            message.Subject = mailTitle;
            message.Body = new TextPart("plain") { Text = mailMessage };
    
            using (var client = new SmtpClient())
            {
                client.Connect(host , port, SecureSocketOptions.StartTls);
                client.Authenticate(username, password);
    
                client.Send(message);
                client.Disconnect(true);
            }
    

    【讨论】:

    • 如果您收到“SMTP 服务器已意外断开连接”。可能是您的提供商没有 TLS。即使我的提供商说 TLS 兼容,它也不起作用,所以我尝试使用 SecureSocketOptions.SslOnConnect 并让它工作。如果它可以帮助某人。
    【解决方案5】:

    您可能还需要更改 Gmail 帐户上的“不太安全的应用”设置。 EnableSsl,使用端口 587 并启用“不太安全的应用程序”。如果您使用 google 搜索不太安全的应用程序部分,则会有 google 帮助页面将您直接链接到您帐户的页面。那是我的问题,但由于以上所有答案,现在一切正常。

    【讨论】:

    • 谢谢比尔。这仍然适用于我的标准 gmail 帐户。如果您不使用“不太安全的应用程序”设置,则必须使用 OAuth2 两部分身份验证。当您只想从网站发送确认电子邮件时,这是不切实际的。
    • “不太安全的应用程序”设置在哪里。我正在我的 gmail 帐户中寻找它。
    • 我找到了“不太安全的应用程序”设置 - 它不在 Gmail 设置中,而是在 Google 帐户设置中:我的帐户 > 登录和安全myaccount.google.com/…
    【解决方案6】:

    针对 Outlook Mailer 的答复

    var SmtpClient = new SmtpClient{
                    DeliveryMethod = SmtpDeliveryMethod.Network,
                    Credentials = new System.Net.NetworkCredential("email", "password"),
                    Port = 587,
                    Host = "smtp.office365.com",
                    EnableSsl = true }
    

    https://admin.exchange.microsoft.com/#/settings -> 点击邮件流

    -> 检查 - 启用旧 TLS 客户端的使用

    -> 保存

    【讨论】:

      【解决方案7】:

      删除

      client.UseDefaultCredentials = false; 
      

      似乎为我解决了这个问题。

      【讨论】:

        【解决方案8】:

        把这个放在我的方法的开头为我解决了这个问题

        System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12
        

        【讨论】:

        • 这似乎是2022年的正确答案。我还添加了一些其他协议> ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 |安全协议类型.Tls |安全协议类型.Tls11 | SecurityProtocolType.Tls12;
        • 测试了其他答案,但只有这个对我有用
        【解决方案9】:

        您的 SMTP 库是否支持加密连接?邮件服务器可能期待安全的 TLS 连接,因此在没有 TLS 握手的情况下关闭连接

        【讨论】:

        • 它只是默认的.NET SmtpClient 库,它确实支持加密,服务器确实需要加密,我设置了client.EnableSssl = true;。虽然我想我会用 Wireshark 进一步说明这一点。
        【解决方案10】:

        如果您在同一个盒子上使用 SMTP 服务器,并且您的 SMTP 绑定到 IP 地址而不是“任何已分配”,则它可能会失败,因为它试图使用 SMTP 所在的 IP 地址(如 127.0.0.1)目前没有工作。

        【讨论】:

          【解决方案11】:

          为了提升 jocull 在评论中提到的内容,我正在做这个线程中提到的所有事情并删除......因为我的循环被一遍又一遍地运行;第一次通过循环后,有时会失败。总是第一次通过循环。

          需要明确:循环包括创建 SmtpClient,然后使用正确的数据执行 .Send。 SmtpClient 是在 try/catch 块内创建的,用于捕获错误并确保对象在循环底部之前被销毁。

          在我的情况下,解决方案是确保在循环中的每次之后处理 SmtpClient(通过 using() 语句或通过手动处理)。即使 SmtpClient 对象在循环中被隐式销毁,.NET 似乎也会留下一些东西以与下一次尝试发生冲突。

          【讨论】:

            【解决方案12】:

            将端口号从 465 更改为 587

            【讨论】:

              【解决方案13】:

              在我的例子中,客户忘记在他们的 SMTP 设置中添加新的 IP 地址。在设置 smtp 的服务器中打开 IIS 6.0,右键单击 Smtp 虚拟服务器,选择属性,访问选项卡,单击连接,添加新服务器的 IP 地址。然后单击中继,同时添加新服务器的 IP 地址。这解决了我的问题。

              【讨论】:

                【解决方案14】:

                如果您的邮件服务器是 Gmail (smtp.google.com),当您达到邮件限制时,您会收到此错误消息。 Gmail 允许通过 SMTP 每 24 小时最多发送 2000 封邮件。

                【讨论】:

                  【解决方案15】:

                  我在使用 smtp.office365.com 时遇到了这个问题,使用端口 587 和 SSL。我能够使用 portal.office.com 登录该帐户,并且可以确认该帐户具有许可证。但是当我触发发送电子邮件的代码时,我不断收到 net_io_connectionclosed 错误。

                  我花了一些时间才弄明白,但 Exchange 管理员找到了罪魁祸首。我们使用的是 O365,但 Exchange 服务器处于混合环境中。尽管我们尝试使用的帐户已同步到 Azure AD 并具有有效的 O365 许可证,但由于某种原因,邮箱仍驻留在混合 Exchange 服务器上 - 而不是 Exchange Online。在交换管理员使用“移动邮箱”命令将邮箱从混合交换服务器移动到 O365 之后,我们可以使用代码使用 o365 发送电子邮件。

                  【讨论】:

                    【解决方案16】:

                    如果您使用的是 Sendgrid 并且收到此错误,那是因为 sendgrid 不再允许基本身份验证。我们需要创建 API 密钥并将其用作 NetworkCredential。 username="apikey" 密码将是您的 API 密钥 参考——https://docs.sendgrid.com/for-developers/sending-email/integrating-with-the-smtp-api

                    【讨论】:

                      【解决方案17】:

                      我在使用 .NET smtp 客户端 + office 365 邮件服务器时遇到了同样的问题:有时邮件发送成功,有时不成功(间歇性发送失败)。

                      问题已通过将所需的 TLS 版本设置为 1.2 仅 得到解决。原始代码(在 2021 年年中开始失败 - BTW)允许 TLS 1.0、TLS 1.1 和 TLS 1.2。

                      代码(CLI/C++)

                          int tls12 = 3072; // Tls12 is not defined in the SecurityProtocolType enum in CLI/C++ / ToolsVersion="4.0"  
                          System::Net::ServicePointManager::SecurityProtocol = (SecurityProtocolType) tls12;
                      

                      (注意:问题已在 Win 8.1 机器上重现并修复)

                      【讨论】:

                        【解决方案18】:

                        试试这个:这是我用来向多个用户发送电子邮件的代码。

                         public string gmail_send()
                            {
                                using (MailMessage mailMessage =
                                new MailMessage(new MailAddress(toemail),
                            new MailAddress(toemail)))
                                {
                                    mailMessage.Body = body;
                                    mailMessage.Subject = subject;
                                    try
                                    {
                                        SmtpClient SmtpServer = new SmtpClient();
                                        SmtpServer.Credentials =
                                            new System.Net.NetworkCredential(email, password);
                                        SmtpServer.Port = 587;
                                        SmtpServer.Host = "smtp.gmail.com";
                                        SmtpServer.EnableSsl = true;
                                        mail = new MailMessage();
                                        String[] addr = toemail.Split(','); // toemail is a string which contains many email address separated by comma
                                        mail.From = new MailAddress(email);
                                        Byte i;
                                        for (i = 0; i < addr.Length; i++)
                                            mail.To.Add(addr[i]);
                                        mail.Subject = subject;
                                        mail.Body = body;
                                        mail.IsBodyHtml = true;
                                        mail.DeliveryNotificationOptions =
                                            DeliveryNotificationOptions.OnFailure;
                                        //   mail.ReplyTo = new MailAddress(toemail);
                                        mail.ReplyToList.Add(toemail);
                                        SmtpServer.Send(mail);
                                        return "Mail Sent";
                                    }
                                    catch (Exception ex)
                                    {
                                        string exp = ex.ToString();
                                        return "Mail Not Sent ... and ther error is " + exp;
                                    }
                                }
                            }
                        

                        【讨论】:

                        • SmtpClient 也是一次性的,所以它应该被包裹在一个 using 块中
                        【解决方案19】:

                        如果上述所有解决方案都不适合您,请尝试将以下文件更新到您的服务器(我的意思是发布,在此之前的构建会有所帮助)。

                        bin-> projectname.dll 
                        

                        更新后你会看到这个错误。 正如我用这个解决方案解决的那样。

                        【讨论】:

                        • 令人惊讶的是这对我有用!允许不安全的应用程序已打开,并且端口已设置为 587。
                        • 谢谢,刚刚意识到我不是唯一一个遇到这个问题的人。很乐意提供帮助。
                        【解决方案20】:

                        对于 Outlook 使用以下不会给我错误的设置

                        SMTP 服务器名称 smtp-mail.outlook.com

                        SMTP 端口 587

                        【讨论】:

                          【解决方案21】:

                          此错误非常普遍。可能是由于多种原因,例如 邮件服务器不正确。 一些托管公司使用 mail.domainname 格式。 如果你只是使用域名,它不会工作。 检查凭据 主机名 如果需要,用户名密码 请咨询托管公司。

                          <smtp from="info@india.uu.com">
                                  <!-- Uncomment to specify SMTP settings -->
                                  <network host="domain.com" port="25" password="Jin@" userName="info@india.xx.com"/>
                                </smtp>
                              </mailSettings>
                          

                          【讨论】:

                            【解决方案22】:

                            在我的情况下,Web 服务器 IP 在邮件服务器上被阻止,需要由您的托管公司解除阻止并将其列入白名单。另外,使用端口 587。

                            【讨论】:

                              【解决方案23】:

                              我最初的问题是间歇性发送失败。例如。第一个 Send() 成功,第二个 Send() 失败,第三个 Send() 成功。起初我以为我没有正确处理。于是我求助于using()。

                              反正后来我加了UseDefaultCredentials = false,Send()终于稳定了。 不知道为什么。

                              【讨论】:

                                【解决方案24】:

                                我最近不得不在我们所有的应用程序上设置新的邮件设置,并在多个项目中遇到了这个错误。

                                对我来说,解决方案是在我的一些项目中将目标框架更新为较新的版本。

                                我还有一个 ASP.net 网站项目,其中更新目标框架还不够,我还必须将以下代码添加到 web.config &lt;httpRuntime targetFramework="4.8"/&gt;

                                【讨论】:

                                  【解决方案25】:

                                  准备: 1. HostA 是 SMTP 虚拟服务器,默认端口为 25 2. HostB 是我使用 SmtpClient 发送邮件的工作站 并模拟不稳定的网络 I use clumsy

                                  案例 1 如果 HostB 是 2008R2 当我发送电子邮件时。 那么就会出现这个问题。

                                  案例 2 如果 HostB 是 2012 或更高版本 当我发送电子邮件时。 然后邮件就发出去了。

                                  结论:这个根本原因与Windows Server 2008R2有关。

                                  【讨论】:

                                    猜你喜欢
                                    • 2013-07-04
                                    • 2016-02-21
                                    • 1970-01-01
                                    • 2022-08-19
                                    • 2015-03-02
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 1970-01-01
                                    相关资源
                                    最近更新 更多