System.Net.Mail – Oops


The System.Net.Mail classes of the .NET framework provide the ability for programmers to send email. The classes are robust and support a wide range of authentication mechanisms including basic (digest), NTLM, Login and Negotiate.
What’s surprising is that the Negotiate doesn’t work with Exchange 2007 or Exchange 2010.
That is, out-of-the-box you can’t send mail messages via an Exchange 2007 SMTP connector which is secured. If you do try to send a mail message to Exchange on port 587 the SmtpClient throws a null reference exception and the protocol receive log will contain lines like:

1
2
3
4
5
<,AUTH gssapi,
>,334 <authentication response>,
>,334 <authentication response>,
*,,Inbound Negotiate failed because of IllegalMessage
>,535 5.7.3 Authentication unsuccessful,
<,AUTH gssapi,
>,334 <authentication response>,
>,334 <authentication response>,
*,,Inbound Negotiate failed because of IllegalMessage
>,535 5.7.3 Authentication unsuccessful,

Unfortunately there’s no option (which works) to specify an alternative authentication mechanism so the workaround is horrible hack.

Maybe someone who knows more can suggest a better or more official way to fix the problem of authenticating with an Exchange SMTP connector. In the meantime the hack is described here.

IdHunter describes the problem in this post. In summary, Exchange implements SPNEGO and advertises the ‘Negotiate’ authentication mechanism. However the System.Net.Mail classes are expecting to be able to use GGSAPI to handle ‘Negotiate’. As a result, the client sends packets the server is not expecting leading to the IllegalMessage entry in the server log and failure.

IdHunter suggests subclassing the NegotiateStream class to fix the problem which is an option for him. However the .NET SMTP classes involved, such as SmtpTransport, ISmtpAuthenticationModule (and the implementations such as SmtpNegotiateAuthenticationModule) are marked private so cannot be overridden or replaced.

Instead knom suggests a hack in this post which does work.

The System.Net.Mail classes include 4 authentication modules: SmtpNegotiateAuthenticationModule, SmtpNtlmAuthenticationModule, SmtpDigestAuthenticationModule and SmtpLoginAuthenticationModule. These are instantiated by SmtpAuthenticationManager and recorded by StmpTransport in a private array variable called authenticationModules. The SmtpClient has a private variable called ‘transport’ which is a reference to the StmpTransport instance. Using reflection it’s possible to access the private ‘transport’ instance and then grab the array of authentication modules.

The first entry in the authentication modules array is an instance of SmtpNegotiateAuthenticationModule and because the Exchange SMTP connector advertises ‘Negotiate’ this first authentiation module is used which leads to failure. The trick is to remove the instance or move it from the top spot.

In the example knom provides all array entries are replaced by the one to be used. I want to use NTLM and have found it to be enough to swap the one I need into the top spot.

There are other suggestions out there. For example, some posts suggest specifying the authentication modules in the application configuration file. However the SmtpAuthenticationManager does not look to the configuration file when instantiating the authentication modules as the list is hard-coded.

Another suggests explicitly specifying the authentication mechanism to use in the credentials:

smtp.Credentials = (System.Net.ICredentialsByHost)nc.GetCredential(smtpHost, smtpPort, "ntlm");

While yet another suggests creating a class which implements ICredentialsByHost to ignore the gssapi protocol request.

Both the last two suggestions fail – at least when NTLM is the preferred authentication. Both fail because the SmtpClient implementation *will not allow an ICredentialsByHost implementation to ignore GSSAPI* if its in the list. Use Reflector to check the GetConnection() method of StmpClient implementation. You will see the existence of the GGSAPI authentication module causes a local variable ‘sawNegotiate’ to be set which precludes the use of other modules.

Information and Links

Join the fray by commenting, tracking what others have to say, or linking to it from your blog.


Other Posts

Reader Comments

Sorry, comments are closed.