jstedfast/MailKit · error · SaslException

IncorrectHash

IncorrectHash

Error message

Server response did not contain the expected hash.

What it means

After parsing the required 'rspauth' directive in the final DIGEST-MD5 response, MailKit recomputes the expected hash from the Credentials.Password and compares it to the value the server sent. This SaslException (SaslErrorCode.IncorrectHash) is thrown when the server's rspauth value does not match the locally computed hash, meaning the server failed to prove it knows the shared secret.

Solutions

  1. Verify the username and password passed to Authenticate/Credentials are correct for the target server.
  2. Check for non-ASCII characters in the password and ensure consistent charset handling (try ASCII-safe password to confirm).
  3. Confirm the server implementation conforms to RFC 2831 rspauth computation; test with another client.
  4. Re-check that the account password hasn't changed and any credential store/cache is up to date.
  5. Switch to a different SASL mechanism (e.g. PLAIN over TLS) to sidestep DIGEST-MD5 hash negotiation issues.

Example fix

// before: wrong password silently produces IncorrectHash
var digest = new SaslMechanismDigestMd5 ("user", "paasword"); // typo
await client.Authenticate (digest);

// after: correct credentials from secure source
var digest = new SaslMechanismDigestMd5 ("user", passwordFromSecretStore);
await client.Authenticate (digest);
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-validate credentials before the exchange
if (string.IsNullOrEmpty (password) || password != confirmedPassword)
	throw new InvalidOperationException ("Password missing or mismatched; fix credentials before authenticating");

Try / catch

try {
	await client.Authenticate (new SaslMechanismDigestMd5 (user, pass));
} catch (SaslException ex) when (ex.ErrorCode == SaslErrorCode.IncorrectHash) {
	// server rspauth did not match: wrong password or charset issue
	logger.LogError ("Server failed rspauth verification; check credentials/charset");
	throw;
}

Prevention

When it happens

Trigger: Challenge receives a final token whose rspauth value differs from response.ComputeHash(encoding, Credentials.Password, false) — i.e. wrong password supplied, or the server computed its hash with different credentials/charset/nonce values.

Common situations: Typo'd or stale password in Credentials; server and client disagreeing on charset (e.g. UTF-8 vs ISO-8859-1) for non-ASCII passwords; server bug computing rspauth with a different nonce/cnonce; account password changed mid-session.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of jstedfast/MailKit@9d3859a785 (2026-09-15). Data as JSON: /api/errors/6db6f4820b4b9d3e. Report an issue: GitHub.

Appendix: source

Thrown at MailKit/Security/SaslMechanismDigestMd5.cs:173

				state = LoginState.Final;

				return response.Encode (encoding);
			case LoginState.Final:
				if (token == null || token.Length == 0)
					throw new SaslException (MechanismName, SaslErrorCode.MissingChallenge, "Server response did not contain any authentication data.");

				var text = encoding!.GetString (token, startIndex, length);
				string? key, value;

				if (!DigestChallenge.TryParseKeyValuePair (text, out key, out value))
					throw new SaslException (MechanismName, SaslErrorCode.IncompleteChallenge, "Server response contained incomplete authentication data.");

				if (!key.Equals ("rspauth", StringComparison.OrdinalIgnoreCase))
					throw new SaslException (MechanismName, SaslErrorCode.InvalidChallenge, "Server response contained invalid data.");

				var expected = response!.ComputeHash (encoding, Credentials.Password, false);
				if (value != expected)
					throw new SaslException (MechanismName, SaslErrorCode.IncorrectHash, "Server response did not contain the expected hash.");

				IsAuthenticated = true;
				break;
			}

			return null;
		}

		/// <summary>
		/// Reset the state of the SASL mechanism.
		/// </summary>
		/// <remarks>
		/// Resets the state of the SASL mechanism.
		/// </remarks>
		public override void Reset ()
		{
			state = LoginState.Auth;
			challenge = null;

View on GitHub (pinned to 9d3859a785)