SmtpClient无法发送;雷鸟可以

SmtpClient can't send; Thunderbird can

这应该很正常吧?

public static SmtpClient GetSmtpClient()
{
    var client = new SmtpClient
    {
        Host = _smtpServer,
        UseDefaultCredentials = false,
        Credentials = new NetworkCredential(_smtpUsername, _smtpPassword),
        Port = _smtpPort, // port 25
        EnableSsl = _smtpSsl // false
    };
    return client;
}
...
var m = new MailMessage 
{
    // contents of mail message
}
using (var server = GetSmtpClient())
{
    server.Send(m);
}

但是 server.Send() 正在抛出一个 SmtpException:

Failure sending mail. ---> System.IO.IOException: Unable to read data from the transport connection: net_io_connectionclosed

我的凭据有问题吗? SMTP 服务器上的 IP 块?也许我的 ISP 阻止了对端口 25 的传出请求?我在与我的调试环境相同的机器上下载并安装了 Thunderbird,并在那里设置了相同的 SMTP 凭据,它运行完美。

为什么它在 Thunderbird 中有效,但在我的代码中却无效?

更新:按照@tzachs的建议,我下载了Wireshark,发现交易进度在一定程度上是相同的。

雷鸟:

TCP 62  25 → 50924 [SYN, ACK] Seq=0 Ack=1 Win=5840 Len=0 MSS=1360 SACK_PERM=1
SMTP    143 S: 220 smtp.somedomain.com ESMTP Sendmail 8.13.8/8.13.8; Sat, 5 Dec 2015 15:46:22 -0500
TCP 54  25 → 50924 [ACK] Seq=90 Ack=18 Win=5840 Len=0
SMTP    289 S: 250 smtp.somedomain.com Hello my-computer.myisp.com [x.x.60.61], pleased to meet you | 250 ENHANCEDSTATUSCODES | 250 PIPELINING | 250 8BITMIME | 250 SIZE | 250 DSN | 250 ETRN | 250 AUTH LOGIN PLAIN | 250 DELIVERBY | 250 HELP
SMTP    82  S: 235 2.0.0 OK Authenticated
etc.

SmtpClient:

TCP 62  25 → 50889 [SYN, ACK] Seq=0 Ack=1 Win=5840 Len=0 MSS=1360 SACK_PERM=1
SMTP    143 S: 220 smtp.somedomain.com ESMTP Sendmail 8.13.8/8.13.8; Sat, 5 Dec 2015 15:45:08 -0500
TCP 54  25 → 50889 [ACK] Seq=90 Ack=21 Win=5840 Len=0
SMTP    289 S: 250 smtp.somedomain.com Hello my-computer.myisp.com [x.x.60.61], pleased to meet you | 250 ENHANCEDSTATUSCODES | 250 PIPELINING | 250 8BITMIME | 250 SIZE | 250 DSN | 250 ETRN | 250 AUTH LOGIN PLAIN | 250 DELIVERBY | 250 HELP
TCP 54  25 → 50889 [FIN, ACK] Seq=325 Ack=62 Win=5840 Len=0
TCP 54  25 → 50889 [ACK] Seq=326 Ack=63 Win=5840 Len=0

请注意,在 SmtpClient 跟踪中的 "pleased to meet you" 行之后,没有任何关于身份验证的内容。不是 "accepted",不是 "failed" - 什么都没有。只是终止连接。

这有什么启示吗?

另一个更新: Smtp 服务器是 运行 SendMail,FWIW。该错误特定于此特定的 Smtp 主机;当我指向不同的服务器时,代码工作正常。

[更新]this 案例与您发布的 Wireshark 事务进行比较,SMTP 服务器关闭了连接。问题是:为什么?也许您的电子邮件有问题。检查您是否填写了发件人、收件人、主题和正文。

希望对您有所帮助。

[旧] 在尝试以编程方式发送消息时,我遇到了类似的情况。

检查您的邮件主机的设置,是否允许每个客户端访问。

另见 so

"Under the "访问安全性较低的应用程序”部分,您可以启用从其他 devices/applications...(例如您的 C# 应用程序)访问您的帐户。”

我还添加了一个 certificat-Call-Back,就像 ukhardy 写的那样。但这只是必要的,如果你 EnableSsl,回调应该做一些验证。

ServicePointManager.ServerCertificateValidationCallback = 
delegate(object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) 
{ return true; };
 smtp.Send(mail);

检查禁用防火墙和防病毒是否有效。

客户端超时默认值是:

client.Timeout = 10000;

另一个用户遇到了由 Program-Structure 引起的相同异常,请参阅 putting client Creation outside loop helped。可能会在静态工厂帮助之外重构客户端生成。

同时检查 DeliveryMethod:

client.DeliveryMethod = SmtpDeliveryMethod.Network;

你试过了吗Mailgun。它将为您发送邮件,并显示电子邮件是从指定的发件人发送的。这是一个非常简单的设置。

您还可以添加电子邮件附件。

只需将其添加到您的网络配置中

Web.config 这将适用于 smtp4dev

<system.net>
  <mailSettings>
    <smtp>
      <network host="localhost" port="25" />
    </smtp>
  </mailSettings>
</system.net>

Web.Release.config

<system.net>
  <mailSettings>
    <smtp deliveryMethod="Network" from="noreply@email_you_chose.com" xdt:Transform="Replace">
      <network host="smtp.mailgun.org" userName="postmaster@the_address_you_chose.com" password="password the site gives you" />
    </smtp>
  </mailSettings>
</system.net>

Service.cs

private MailMessage MailMessageFactory(EmailDTO emailDto)
{
    var text = emailDto.Body;
    var html = emailDto.Body;

    var mailMessage = new MailMessage();
    foreach (var recipient in emailDto.To)
    {
        mailMessage.To.Add(new MailAddress(recipient));
    }
    mailMessage.From = new MailAddress(emailDto.From);
    mailMessage.Subject = emailDto.Subject;
    mailMessage.Body = emailDto.Body;
    mailMessage.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(text, null, MediaTypeNames.Text.Plain));
    mailMessage.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(html, null, MediaTypeNames.Text.Html));
    mailMessage.IsBodyHtml = true;

    return mailMessage;
}

EmailDto.cs

public class EmailDTO
{
    public string From { get; set; }

    public IList<string> To { get; set; }

    public string Subject { get; set; }

    public string Body { get; set; }
}

我在使用不同的 SMTP 服务器时确实遇到过一些问题。根据我的经验,默认的 .net smtpclient API 有时不会告诉您真正发生了什么(公平地说,这可能是为我们简化事情的副作用)。 过去对我有帮助的,特别是在故障排除阶段,是使用 .Net SMTP API,它允许我调试它直到 rcpt 命令,并为我提供更丰富的异常信息。

为此,我建议您下载该项目的源代码并调试其 SMTP 示例:MailSystem.Net 有一个名为 ActiveUp.Net.Samples 的 windows 表单项目,只需构建并执行它,您就可以继续进行几分钟。

如果您更喜欢以编程方式使用它,它与 .net smtpclient 非常相似(并且它确实有过载来传递凭据):

        ActiveUp.Net.Mail.Message message = new ActiveUp.Net.Mail.Message();

        // We assign the sender email
        message.From.Email = this.fromEmailTextbox.Text;

        // We assign the recipient email
        message.To.Add(this.toEmailTextbox.Text);

        // We assign the subject
        message.Subject = this.subjectTextbox.Text;

        // We assign the body text
        message.BodyText.Text = this.bodyTextTextbox.Text;

        // We send the email using the specified SMTP server
        this.AddLogEntry("Sending message.");

        try
        {
            SmtpClient.Send(message, this.smtpServerAddressTextbox.Text);

            this.AddLogEntry("Message sent successfully.");
        }
        catch (SmtpException ex)
        {
            this.AddLogEntry(string.Format("Smtp Error: {0}", ex.Message));
        }
        catch (Exception ex)
        {
            this.AddLogEntry(string.Format("Failed: {0}", ex.Message));
        }

希望对您有所帮助。

当我切换到亚马逊电子邮件服务时,我遇到了同样的问题。我以前的电子邮件服务器需要端口,但亚马逊电子邮件服务 运行 不需要。根据您的电子邮件 SMTP 服务器,端口和启用 SSL 设置是必需的。 如果需要,添加端口和 EnableSSL。

public static SmtpClient GetSmtpClient()
{
   var client= new SmtpClient();
   client.Host= _smtpServer;
   client.UseDefaultCredentials = false;
   if (smtpUseDefaultCredential)
   { 
      client.UseDefaultCredentials = true;
   }
   else
   {
      client.UseDefaultCredentials = false;
      client.Credentials = new NetworkCredential(smtpUser, smtpPassword);
   }

   if(isPortRequired)
    {
     client.Port= _smtpPort;
    }
    if(isEnableSslRequired)
    {
     client.EnableSsl= true;
    }

    return client;
}

您的 ISP 是否可能实施了 POP before SMTP 之类的功能?我看到您没有在 Thunderbird 对话中发送任何身份验证流量,但我确实记得大约十年前有一个 ISP 使用该机制。