jstedfast/MailKit · error · ImapProtocolException

format, args

Error message

format, args

What it means

ImapEngine.AssertToken verifies that the token parsed from the IMAP server's response has the expected ImapTokenType; when it does not, it throws an ImapProtocolException (via UnexpectedToken) with UnexpectedToken set, carrying a formatted message. This means the server sent a response that violates the IMAP protocol grammar at the point being parsed — the library cannot interpret the reply.

Solutions

  1. Verify you are connecting to a real IMAP server on the correct port (993/143) and that TLS settings are correct.
  2. Capture the raw protocol trace (client can be hooked via ImapClient's tracing / ProtocolLogger) to see the malformed server response.
  3. Check for known server quirks (e.g. mail.ru formatting integers as 9.3736e+06); update MailKit, which carries workarounds for many broken servers.
  4. Retry the command if the failure is transient (truncated/garbled response), or reconnect and resume.

Example fix

// before
client.Connect ("mail.example.com", 587, SecureSocketOptions.None); // wrong service/port -> garbage tokens
client.Authenticate ("user", "pass");

// after
client.Connect ("imap.example.com", 993, SecureSocketOptions.SslOnConnect);
client.Authenticate ("user", "pass");
Defensive patterns

Strategy: try-catch

Try / catch

try {
    client.Connect (host, port, SecureSocketOptions.SslOnConnect);
} catch (ImapProtocolException ex) when (ex.UnexpectedToken) {
    logger.LogError ("Malformed IMAP response during connect: {0}", ex.Message);
}

Prevention

When it happens

Trigger: Any of the callers (ParseNumber, ParseNumber64, ParseUidSet, Connect, ConnectAsync, UpdateCapabilities) encountering a token of the wrong type while parsing a server response — e.g. Connect/UpdateCapabilities expecting an untagged CAPABILITY response with an atom token but receiving something else, or ParseUidSet hitting a non-atom token where a UID set was expected.

Common situations: Talking to a broken or non-compliant IMAP server (proxies, gateways, vendor-specific servers) whose responses deviate from RFC 3501; MITM/firewall injecting HTML error pages; connecting to a non-IMAP port; protocol downgrade or truncated responses.

Related errors


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

Appendix: source

Thrown at MailKit/Net/Imap/ImapEngine.cs:612

				if (args[i] is ImapToken token) {
					switch (token.Type) {
					case ImapTokenType.Atom: args[i] = string.Format ("Unexpected atom token: {0}", token); break;
					case ImapTokenType.Flag: args[i] = string.Format ("Unexpected flag token: {0}", token); break;
					case ImapTokenType.QString: args[i] = string.Format ("Unexpected qstring token: {0}", token); break;
					case ImapTokenType.Literal: args[i] = string.Format ("Unexpected literal token: {0}", token); break;
					default: args[i] = string.Format ("Unexpected token: {0}", token); break;
					}
					break;
				}
			}

			return new ImapProtocolException (string.Format (CultureInfo.InvariantCulture, format, args)) { UnexpectedToken = true };
		}

		internal static void AssertToken (ImapToken token, ImapTokenType type, string format, params object[] args)
		{
			if (token.Type != type)
				throw UnexpectedToken (format, args);
		}

		internal static void AssertToken (ImapToken token, ImapTokenType type1, ImapTokenType type2, string format, params object[] args)
		{
			if (token.Type != type1 && token.Type != type2)
				throw UnexpectedToken (format, args);
		}

		internal static uint ParseNumber (ImapToken token, bool nonZero, string format, params object[] args)
		{
			AssertToken (token, ImapTokenType.Atom, format, args);

			// Note: Broken IMAP servers such as mail.ru sometimes incorrectly format integers as numbers with decimals and exponents. (e.g. 9.3736e+06)
			// See https://github.com/jstedfast/MailKit/issues/1838 and https://github.com/jstedfast/MailKit/issues/1840 for details.
			if (!uint.TryParse ((string) token.Value, NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent, CultureInfo.InvariantCulture, out var value) || (nonZero && value == 0))
				throw UnexpectedToken (format, args);

			return value;

View on GitHub (pinned to 9d3859a785)