【问题标题】:Troubleshooting "The server committed a protocol violation" when sending mail with SmtpClient使用 SmtpClient 发送邮件时“服务器违反协议”疑难解答
【发布时间】:2010-03-04 15:40:43
【问题描述】:

我想用SmtpClient 类发送邮件消息。

这是我使用的代码:

SmtpClient smtpClient = new SmtpClient("Host",25);
NetworkCredential basicCredential =
new NetworkCredential("UserName", "Password");
MailMessage message = new MailMessage();
MailAddress fromAddress = new MailAddress("me@domain.com");
smtpClient.UseDefaultCredentials = false;
smtpClient.Credentials = basicCredential;
message.From = fromAddress;
message.Subject = "test send";
message.IsBodyHtml = true;
message.Body = "<h1>hello</h1>";
message.To.Add("mail@domain.com");
smtpClient.Send(message);

但它总是抛出异常:

服务器违反协议服务器响应是:UGFzc3dvcmQ6

我找不到原因。请,如果有人遇到过这样的事情,请告诉我该怎么做。

【问题讨论】:

    标签: c# asp.net smtpclient


    【解决方案1】:

    我遇到了同样的问题,我的意思是设置 user@domain 而不是 user,我的意思是

    旧代码

    new NetworkCredential("UserName@domain.com", "Password");
    

    新代码

    new NetworkCredential("UserName", "Password");
    

    【讨论】:

      【解决方案2】:

      这在我看来就像 SmtpClient 身份验证在某种程度上失控了。

      一些身份验证机制是“客户端:使用用户名和密码请求身份验证,服务器:成功/失败”其他是“客户端:使用用户名请求身份验证,服务器:请求密码,客户端:使用密码回复,服务器:成功/失败” .

      看起来 SmtpClient 期待前者,而您的服务器期待后者。

      作为dave wenta suggested,会话日志会告诉您 SmtpClient 尝试使用的身份验证机制,但它也会说明服务器支持的身份验证机制。

      通常发生的情况是服务器提供了许多身份验证选项,客户端选择要使用的身份验证选项。那里的行为应该由选择的协议决定。我希望 SmtpClient 类为您解决这个问题,但恐怕我从未使用过那个特定的类。

      还请记住 - 如果您要在此处发布日志,请在登录会话之前更改为一次性密码,因为 base64 编码的纯文本密码可以很容易地更改回人类可读的纯文本密码。

      【讨论】:

      • 感谢您的回复我相信正如您所说,服务器正在等待 Base64 身份验证信息
      • 这也不起作用,我也在日志中检查过,但它没有显示任何服务器响应。你能帮忙吗?
      【解决方案3】:

      UGFzc3dvcmQ6 是“密码:”base 64 编码(不带引号),这意味着密码可能错误或未发送编码。尝试使用 base 64 编码密码:

      string password = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("Password));
      

      【讨论】:

      • 抱歉,错误消失了,但抛出了一个新异常,即发送邮件失败,不知道该怎么做
      【解决方案4】:

      为 System.Net.Mail 启用日志记录。然后查看日志文件。这将准确显示 SMTP 层发生的情况。

      这是一个包含更多信息的链接:

      http://systemnetmail.com/faq/4.10.aspx

      【讨论】:

      • 5 年后,这是一个巨大的帮助 - 发现我正在偷猎连接。
      • @dave wanta 答案中提到的链接已失效。
      【解决方案5】:

      thousand of hit on google for UGFzc3dvcmQ6

      似乎服务器期望加密(使用 base64)用户名/密码

      【讨论】:

      【解决方案6】:

      遇到了同样的问题。通过以下步骤解决了它: 1) 通过使用 Telnet 或 putty 或任何其他终端连接到 SMTP 服务器,找出服务器为 SMTP 身份验证提供的功能:

      telnet xxx.yyy.zzz.aaa 587 
      

      (xxx.yyy.zzz.aaa = SMTP 服务器的 IP 地址,587 = 端口号)

      ehlo testing
      

      250-AUTH NTLM CRAM-MD5 LOGIN
      

      SMTP 客户端尝试首先采用最安全的协议。就我而言:

      1. System.Net.Mail.SmtpNegotiateAuthenticationModule
      2. System.Net.Mail.SmtpNtlmAuthenticationModule
      3. System.Net.Mail.SmtpDigestAuthenticationModule
      4. System.Net.Mail.SmtpLoginAuthenticationModule
      

      看起来好像 SMTP 客户端尝试 NTLM,而服务器尝试运行 LOGIN。

      通过 hack(参见https://blogs.msdn.microsoft.com/knom/2008/04/16/hacking-system-net-mail-smtpclient/),可以关闭所有协议,除了服务器假定的协议(在这种情况下为登录):

      FieldInfo transport = smtpClient.GetType().GetField("transport", BindingFlags.NonPublic | BindingFlags.Instance);
      
      FieldInfo authModules = transport.GetValue(smtpClient).GetType().GetField("authenticationModules",BindingFlags.NonPublic | BindingFlags.Instance);
      
      Array modulesArray = authModules.GetValue(transport.GetValue(smtpClient)) as Array;
      foreach (var module in modulesArray)
      {
          Console.WriteLine(module.ToString());
      }
      // System.Net.Mail.SmtpNegotiateAuthenticationModule
      // System.Net.Mail.SmtpNtlmAuthenticationModule
      // System.Net.Mail.SmtpDigestAuthenticationModule
      // System.Net.Mail.SmtpLoginAuthenticationModule
      
      // overwrite the protocols that you don't want
      modulesArray.SetValue(modulesArray.GetValue(3), 0);
      modulesArray.SetValue(modulesArray.GetValue(3), 1);
      modulesArray.SetValue(modulesArray.GetValue(3), 2);
      

      【讨论】:

      • 上面有一些问题(当然从 .netcore 2.1 开始,这些字段前面有一个下划线。所以上面需要“_transport”和“_authenticationModules”,否则上面或多或少可以工作。跨度>
      【解决方案7】:

      当您根本不提供密码时,也会发生这种情况。在我的情况下,我使用来自 web.config smtp 块的凭据,并且在我的部署服务器上(使用 octopus deploy)忘记填充密码属性。

      【讨论】:

        【解决方案8】:

        对于在 google 上遇到此问题的其他人。我通过以“用户名”格式而不是“域\用户名”格式提供我的用户名来解决此问题

        $Credential = Get-Credential
        
        Send-MailMessage -SmtpServer exchange.contoso.com -Credential $Credential -From 'user@contoso.com' -To 'recipient@domain.com' -Subject 'Test email' -Port 587 -UseSsl
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-08-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-01-29
          • 2011-04-01
          相关资源
          最近更新 更多