SmtpException:无法从传输连接中读取数据:net_io_connectionclosed


102

我正在使用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”。

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

Answers:


189

编辑:超级Redux版本

尝试使用端口587而不是465。在技术上,不建议使用端口465。


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

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

其次,为那些将来遇到此问题的人提供了一个简短的SMTP历史课程:

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

就我而言,我的用户试图将软件连接到强制进行即时SSL连接的服务器,这是Microsoft在.NET中不支持的旧方法。


如何确定我要连接的服务器是否存在相同的问题?我正在尝试将SmtpClient与yahoo和/或gmail结合使用,并得到描述的错误。当我尝试使用2013 Exchange服务器时,我的代码可以正常工作。
raider33 2014年

11
测试的最简单方法是尝试使用端口587,而不是465。虽然某些SMTP服务器在465(有时甚至是25)上支持TLS,但仅要求端口587支持TLS。除此之外,自1998年以来(en.wikipedia.org/wiki/SMTPS)就不赞成使用端口465 ,尽管实际上许多服务器都为旧客户端启用了它。
Jake C'3

1
是的,更改为587可以解决问题。感谢您指出正确的方向。
raider33 2014年

2
587可以工作,尽管smtp.att.yahaoo.com说使用465。谢谢,老兄。
2014年

1
有关实际的解决方案,请参阅stackoverflow.com/a/1014876/247702(使用不建议使用的System.Web.Mail),该System.Web.Mail支持隐式SSL。
user247702 2015年

20

将端口从465更改为587,它将起作用。


3
我不确定发生了什么,但是使用gmail smtp可以解决此问题。您能解释一下为什么行吗?
犯罪记录2016年

20

对于偶然发现本文的人,寻找解决方案,您已经通过Azure设置了SMTP sendgrid。

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

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

希望这可以帮助!


2
这看似很愚蠢,但您可能要检查的另一件事是SMTP SendGrid设置的密码是否正确。我们的设置本来可以正常工作,然后有一天我们开始收到OP的异常消息。当最终发现密码不正确时,在WWW上的搜索主要指向查看其他SMTP服务器配置。团队中的某人已将配置文件中的密码更改为第一个字母不大写的变体。
methon.dagger

1
在我的情况下,用户名不正确并且有错字。但是错误的密码也会使“无法从传输连接读取数据:net_io_connectionclosed”。错误。因此,请同时检查用户名和密码。对于Azure用户,用户名的格式为“ azure_guid-withoutdashes@azure.com”(例如:azure_e9e062db4bfd491296bec77bcff49ed9@azure.com)
Raj Rao

10

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


谢谢比尔。这仍然适用于我的标准gmail帐户。如果您不使用“安全性较低的应用”设置,则必须使用OAuth2两部分身份验证。当您只想从网站发送确认电子邮件时,这是不切实际的。
Dan Randolph

1
“安全性较差的应用程序”在哪里?我在我的Gmail帐户中寻找它。
山姆

1
我找到了“较少安全应用”设置-该设置不在Gmail设置中,而是在Google帐户设置中:我的帐户>登录和安全性 myaccount.google.com/…–
HFloyd,

9

我已经尝试了以上所有答案,但仍然使用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客户端更改为Mailkit解决了问题。由于安全问题,现在不建议Microsoft使用System.Net.Mail Smtp客户端,而应该使用MailKit。使用Mailkit给我提供了更清晰的错误消息,使我可以理解找到问题(许可证问题)的根本原因。您可以通过以Nuget包的形式下载Mailkit

阅读有关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);
        }

3

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


它只是默认的.NET SmtpClient库,它确实支持加密,服务器确实需要加密,并且我已经设置了client.EnableSssl = true;。尽管我认为我将在Wireshark方面进一步说服。
Jake C

3

如果您在同一框上使用SMTP服务器,并且SMTP绑定到IP地址而不是“任何分配的地址”,则它可能会失败,因为它正在尝试使用SMTP当前不起作用的IP地址(例如127.0.0.1)上。


2

为了提升jocull在评论中提到的内容,我正在执行此线程中提到的所有内容并予以删除……因为我的系统处于循环运行的状态;在第一次通过循环后,有时会失败。始终在循环中第一次工作。

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

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




1

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

bin-> projectname.dll 

更新后,您将看到此错误。因为我已经解决了这个问题。


1
令人惊讶的是,这为我工作!允许不安全的应用程序已打开,并且端口已设置为587。
TechyGypo

谢谢,才意识到我不是唯一遇到这个问题的人。乐于帮助。
阿杰·库玛

1

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


0

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

 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;
            }
        }
    }

1
SmtpClient也是一次性的,因此应将其包裹在using一块
jocull 2014年


0

此错误非常笼统。可能是由于多种原因引起的,例如邮件服务器不正确。一些托管公司使用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>

0

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



0

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

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


-1

准备:1. HostA是具有默认端口25的SMTP虚拟服务器2. HostB是一个工作站,在该工作站上我使用SmtpClient发送邮件并模拟不稳定的网络, 我使用笨拙

发送主机时,如果HostB为2008R2,则给出情况1。然后发生此问题。

案例2 如果HostB为2012或更高版本,则在我发送电子邮件时给出。然后,邮件已发送出去。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.