runtime: Unhandled Exception: System.Net.Mail.SmtpException On Linux

smtp ehlo

$ telnet mail-proxy.mycompanydomain.com 25
Trying xx.xx.xx.xx...
Connected to mail-proxy.mycompanydomain.com.
Escape character is '^]'.
220 mail.mycompanydomain.com Microsoft ESMTP MAIL Service ready at Fri, 13 Apr 2018 17:52:12 +0800
EHLO
250-mail.mycompanydomain.com Hello [xx.xx.xx.xx]
250-SIZE 209715200
250-PIPELINING
250-DSN
250-ENHANCEDSTATUSCODES
250-STARTTLS
250-AUTH GSSAPI NTLM LOGIN
250-8BITMIME
250-BINARYMIME
250 CHUNKING

Stacktrace

Unhandled Exception: System.Net.Mail.SmtpException: Failure sending mail. ---> System.ComponentModel.Win32Exception: GSSAPI operation failed with error - An invalid status code was supplied (Cannot find KDC for realm "mycompanydomain.com").
   at System.Net.Security.NegotiateStreamPal.AcquireCredentialsHandle(String package, Boolean isServer, NetworkCredential credential)
   at System.Net.NTAuthentication.Initialize(Boolean isServer, String package, NetworkCredential credential, String spn, ContextFlagsPal requestedContextFlags, ChannelBinding channelBinding)
   at System.Net.Mail.SmtpNegotiateAuthenticationModule.Authenticate(String challenge, NetworkCredential credential, Object sessionCookie, String spn, ChannelBinding channelBindingToken)
   at System.Net.Mail.SmtpConnection.SetContextAndTryAuthenticate(ISmtpAuthenticationModule module, NetworkCredential credential, ContextAwareResult context)
   at System.Net.Mail.SmtpConnection.GetConnection(String host, Int32 port)
   at System.Net.Mail.SmtpTransport.GetConnection(String host, Int32 port)
   at System.Net.Mail.SmtpClient.GetConnection()
   at System.Net.Mail.SmtpClient.Send(MailMessage message)
   --- End of inner exception stack trace ---
   at System.Net.Mail.SmtpClient.Send(MailMessage message)

dotnet --info

$ dotnet --info
.NET Command Line Tools (2.1.300-preview1-008174)

Product Information:
 Version:            2.1.300-preview1-008174
 Commit SHA-1 hash:  b8df89a54f

Runtime Environment:
 OS Name:     debian
 OS Version:  9
 OS Platform: Linux
 RID:         linux-x64
 Base Path:   /usr/share/dotnet/sdk/2.1.300-preview1-008174/

Microsoft .NET Core Shared Framework Host

  Version  : 2.1.0-preview1-26216-03
  Build    : f2c3216183d20416568a4bbf5bb7d153e826f153

Program.cs

using System;
using System.Net;
using System.Net.Mail;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            var host = "mail-proxy.mycompanydomain.com";
            var user = "user@mycompanydomain.com";
            var password = "xxxxxxxxxxxxx";
            var from = "fromuser@mycompanydomain.com";
            var to = "touser@mycompanydomain.com";

            var client = new SmtpClient(host, 25);
            client.UseDefaultCredentials = true;


            client.Credentials = new NetworkCredential(user, password);
            //  client.Credentials = new NetworkCredential(user, password).GetCredential(host, 25, "NLTM");

            var msg = new MailMessage(from, to);
            msg.Subject = "Hello 世界";
            msg.Body = "Hello World" + DateTime.Now.ToString();

            client.Send(msg);


            Console.WriteLine("Hello World!");
        }
    }
}

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 21 (15 by maintainers)

Most upvoted comments

There are three authentication types, 250-AUTH GSSAPI NTLM LOGIN, how can I specify the SmtpClient use the LOGIN one? e.g. by CredentialCache ?

When a server (HTTP server or SMTP server) present multiple schemes for authentication, the “strongest” scheme for security is used by the client.

The order generally is:

  • GSSAPI (Negotiate / Kerberos)
  • NTLM
  • LOGIN (this is similar to HTTP BASIC auth)

If you have a single NetworkCredential set into the SmptClient, then GSSAPI would be used. But if you have a CredentialsCache and only have the user/password marked as LOGIN/Basic, then it would use that scheme.

So you should change this code:

client.Credentials = new NetworkCredential(user, password);

to something that uses a CredentialCache if you want to force LOGIN/Basic to be used.

See: https://docs.microsoft.com/en-us/dotnet/api/system.net.credentialcache.add?view=netcore-2.0#System_Net_CredentialCache_Add_System_String_System_Int32_System_String_System_Net_NetworkCredential_

var cred = new NetworkCredential(user, password);
var cache = new CredentialCache();
cache.Add(host, 25, "Basic", cred);
client.Credentials = cache;

I wonder if we shouldn’t be more resilient to exceptions in our code. The exception comes from: https://github.com/dotnet/corefx/blob/a44c93063d24e29971891bfc2cf8b0aa8771eae9/src/System.Net.Mail/src/System/Net/Mail/SmtpConnection.cs#L275

due to Negotiate setup. We stop enumerating the remaining authentication protocols. Maybe we could treat some/all exceptions here as “SmtpStatusCode.CommandParameterNotImplemented”. Thoughts?