public override void Authenticate (Encoding encoding, ICredentials credentials, CancellationToken cancellationToken = default (CancellationToken))
{
if (encoding == null)
throw new ArgumentNullException (nameof (encoding));
if (credentials == null)
throw new ArgumentNullException (nameof (credentials));
CheckDisposed ();
if (!IsConnected)
throw new ServiceNotConnectedException ("The SmtpClient must be connected before you can authenticate.");
if (IsAuthenticated)
throw new InvalidOperationException ("The SmtpClient is already authenticated.");
if ((capabilities & SmtpCapabilities.Authentication) == 0)
throw new NotSupportedException ("The SMTP server does not support authentication.");
var uri = new Uri ("smtp://" + host);
AuthenticationException authException = null;
SmtpResponse response;
SaslMechanism sasl;
bool tried = false;
string challenge;
string command;
foreach (var authmech in SaslMechanism.AuthMechanismRank) {
if (!AuthenticationMechanisms.Contains (authmech))
continue;
if ((sasl = SaslMechanism.Create (authmech, uri, encoding, credentials)) == null)
continue;
tried = true;
cancellationToken.ThrowIfCancellationRequested ();
// send an initial challenge if the mechanism supports it
if (sasl.SupportsInitialResponse) {
challenge = sasl.Challenge (null);
command = string.Format ("AUTH {0} {1}", authmech, challenge);
} else {
command = string.Format ("AUTH {0}", authmech);
}
response = SendCommand (command, cancellationToken);
if (response.StatusCode == SmtpStatusCode.AuthenticationMechanismTooWeak)
continue;
SaslException saslException = null;
try {
while (!sasl.IsAuthenticated) {
if (response.StatusCode != SmtpStatusCode.AuthenticationChallenge)
throw new SmtpCommandException (SmtpErrorCode.UnexpectedStatusCode, response.StatusCode, response.Response);
challenge = sasl.Challenge (response.Response);
response = SendCommand (challenge, cancellationToken);
}
saslException = null;
} catch (SaslException ex) {
// reset the authentication state
response = SendCommand (string.Empty, cancellationToken);
saslException = ex;
}
if (response.StatusCode == SmtpStatusCode.AuthenticationSuccessful) {
if (QueryCapabilitiesAfterAuthenticating)
Ehlo (cancellationToken);
authenticated = true;
OnAuthenticated (response.Response);
return;
}
var message = string.Format ("{0}: {1}", response.StatusCode, response.Response);
if (saslException != null)
authException = new AuthenticationException (message, saslException);
else
authException = new AuthenticationException (message);
}
if (tried)
throw authException ?? new AuthenticationException ();
throw new NotSupportedException ("No compatible authentication mechanisms found.");
}