9

I'd like to use MailKit to send an email through our Exchange server, using the credentials of the process.

Building up a NetworkCredential with domain/username/password works:

using (var client = new SmtpClient(ProtocolLogger))
{
    client.Connect(server, port);

    // Works
    var creds = new NetworkCredential(username, password, domain);
    client.Authenticate(creds);

    client.Send(msg);        
}

If I use CredentialCache.DefaultNetworkCredentials while running as the same user, it fails with a MailKit.Security.AuthenticationException:

using (var client = new SmtpClient(ProtocolLogger))
{
    client.Connect(server, port);

    // Authentication failure
    client.Authenticate(CredentialCache.DefaultNetworkCredentials);

    client.Send(msg);        
}

The ProtocolLogger output the following (with mail server and base64 encoded strings changed):

Connected to smtp://mymailserver:25/?starttls=when-available
S: 220 mymailserver Microsoft ESMTP MAIL Service ready at Thu, 30 Jun 2016 12:45:04 +0930
C: EHLO [172.1.1.2]
S: 250-mymailserver Hello [172.1.1.2]
S: 250-SIZE 51200000
S: 250-PIPELINING
S: 250-DSN
S: 250-ENHANCEDSTATUSCODES
S: 250-STARTTLS
S: 250-X-ANONYMOUSTLS
S: 250-AUTH NTLM LOGIN
S: 250-X-EXPS GSSAPI NTLM
S: 250-8BITMIME
S: 250-BINARYMIME
S: 250-CHUNKING
S: 250-XEXCH50
S: 250 XRDST
C: STARTTLS
S: 220 2.0.0 SMTP server ready
C: EHLO [172.1.1.2]
S: 250-mymailserver Hello [172.1.1.2]
S: 250-SIZE 51200000
S: 250-PIPELINING
S: 250-DSN
S: 250-ENHANCEDSTATUSCODES
S: 250-AUTH NTLM LOGIN
S: 250-X-EXPS GSSAPI NTLM
S: 250-8BITMIME
S: 250-BINARYMIME
S: 250-CHUNKING
S: 250-XEXCH50
S: 250 XRDST
C: AUTH NTLM {EncodedStringRemoved}
S: 334 {EncodedStringRemoved}
C: {EncodedStringRemoved}
S: 535 5.7.3 Authentication unsuccessful
C: AUTH LOGIN
S: 334 {EncodedStringRemoved}
C: 
S: 334 {EncodedStringRemoved}
C: 
S: 334 {EncodedStringRemoved}
C: QUIT
S: 334 {EncodedStringRemoved}

It's worth noting that System.Net.Mail.SmtpClient uses DefaultNetworkCredentials when setting the UseDefaultCredentials property to true, and this works for me. I want to use MailKit because of the extra features like ProtocolLogging though.

JamesD
  • 440
  • 6
  • 16
  • Do you have outlook account set up in the PC. For Default Credentials to work a outlook account must be setup on the PC. So you have to run outlook first which setups an an outlook account for the user on the local PC which contains the username and email account. The username is then linked to the user account on the PC which has the user credentials including password. The windows credentials is then used a the Default Network Credentials. The mail server and the PC will both use Group Policy to verify password with a Network Password Server. – jdweng Jun 30 '16 at 04:55
  • Thanks for the info. I'm testing on my dev workstation which does have Outlook setup for me. I'm also running the process as me. Interestingly, when I use the built-in `System.Net.Mail.SmtpClient`, it does work, so there must be a difference between what MailKit and the default `SmtpClient` are sending over the wire. I'm not aware of a way to see what `System.Net.Mail.SmtpClient` is sending/receiving, like I can with MailKil. That would be ideal so I could diff them. – JamesD Jun 30 '16 at 06:53
  • You can use a sniffer like fiddler to see the data packets. Usually Corp Networks block mail email port numbers like 587. The way exchange works is it uses proxy server which forwards the email to the exchange. Using Mailkit is probably using 587 and is a Pop Server. Pop servers don't use DefaultCredentials and instead include Username and password and are usually blocked. – jdweng Jun 30 '16 at 09:14
  • 2
    MailKit uses whatever port he gives it. It also doesn't use POP (he's using the SmtpClient, not the Pop3Client). That said, the DefaultCredentials do not work because there is no way to get the user/password strings from the DefaultNetworkCredential object (they return string.Empty). – jstedfast Jun 30 '16 at 10:46
  • @jdweng I tested the built-in `SmtpClient` using integrated security (`UseDefaultCredentials`) on a server where Outlook wasn't installed, and it worked fine. Do you mean the outlook account needs to be set up on **any** machine before this works? – JamesD Jul 01 '16 at 01:06
  • jstedfast " SmtpClient work fine with Pop 3 servers. PopeClient is a 3rd party API that isn't required. – jdweng Jul 01 '16 at 10:48

1 Answers1

6

You cannot use CredentialCache.DefaultNetworkCredentials with MailKit because when MailKit asks the credential to provide the username and password strings that it needs to send to the server, the DefaultNetworkCredentials tells MailKit that the username and password strings are empty and so MailKit tries to authenticate with empty strings.

System.Net.Mail seems to be able to use an internal API to get the real strings that MailKit does not have access to.

Bridge
  • 29,818
  • 9
  • 60
  • 82
jstedfast
  • 35,744
  • 5
  • 97
  • 110
  • 1
    That's a shame, but I can understand why. It's a great feature of the built-in client, as it means not having to store user credentials. Are there any other options with mailkit? – JamesD Jun 30 '16 at 20:34
  • 2
    The required "internal" API is called SSPI and is in fact well-documented. A SASL mecahnism for MailKit using SSPI has been written down by UriHender here: https://github.com/jstedfast/MailKit/issues/332#issuecomment-398300208 – Klaus Gütter Dec 04 '18 at 13:57
  • Unfortunately that solution will only work on Windows, but if you *are* on Windows, then this is fantastic - I missed his comment back in June, so thanks for posting this :-) – jstedfast Dec 05 '18 at 14:51