jstedfast/MailKit · error · SmtpProtocolException
The status codes returned by the server did not match.
Error message
The status codes returned by the server did not match.
What it means
SMTP multi-line replies must repeat the same status code on every line (e.g. 250-a / 250-b / 250 ). If consecutive lines of one reply carry different codes, ReadResponse throws SmtpProtocolException('The status codes returned by the server did not match.'), since RFC 5321 requires consistency within a single reply.
Solutions
- Enable protocol logging (ProtocolLogger) to capture the exact malformed multi-line reply
- Share one SmtpClient/stream per connection — never issue commands from multiple threads concurrently
- Update/replace the offending SMTP server, proxy, or security appliance
- Catch SmtpProtocolException and fail over to another server/connection
Example fix
// before
// two tasks sending commands on the same client concurrently
Task.Run(() => client.NoOp());
await client.SendAsync(message); // interleaved replies
// after
await _sendLock.WaitAsync();
try { await client.SendAsync(message); } finally { _sendLock.Release(); } Defensive patterns
Strategy: try-catch
Try / catch
try
{
await client.SendAsync(message);
}
catch (SmtpProtocolException ex) when (ex.Message.Contains("did not match"))
{
// serialize access or switch server
} Prevention
- Never issue SMTP commands concurrently on one client — serialize with a lock/semaphore
- Protocol-log multi-line replies to identify buggy servers
- Update or replace misbehaving proxies/antivirus gateways
- Use one connection per logical operation set
When it happens
Trigger: A multi-line server reply whose continuation lines have differing codes (e.g. '250-OK' followed by '450-temp'), typically from a buggy or non-compliant server/proxy.
Common situations: Broken SMTP proxies or antivirus gateways rewriting replies; servers with off-by-one bugs in multiline responses (e.g. EHLO capability lists); interleaved data from concurrent use of one connection.
Related errors
- Invalid status code returned by the server.
- Value cannot be null. (Parameter 'message')
- Value cannot be null. (Parameter 'response')
- The IMAP server unexpectedly refused the connection.
- Literal token length
AI-assisted analysis of jstedfast/MailKit@9d3859a785 (2026-09-15).
Data as JSON: /api/errors/5dd814c8ffda8a81.
Report an issue: GitHub.
Appendix: source
Thrown at MailKit/Net/Smtp/SmtpStream.cs:498
bool ReadResponse (ByteArrayBuilder builder, ref bool newLine, ref bool more, ref int code)
{
do {
int startIndex = inputIndex;
if (newLine) {
if (inputIndex + 3 < inputEnd) {
if (!TryParseStatusCode (input, inputIndex, out int value))
throw new SmtpProtocolException ("Unable to parse status code returned by the server.");
inputIndex += 3;
if (value < 100 || !IsLegalAfterStatusCode (input[inputIndex]))
throw new SmtpProtocolException ("Invalid status code returned by the server.");
if (code == 0) {
code = value;
} else if (value != code) {
throw new SmtpProtocolException ("The status codes returned by the server did not match.");
}
newLine = false;
more = input[inputIndex] == (byte) '-';
if (more || input[inputIndex] == (byte) ' ')
inputIndex++;
startIndex = inputIndex;
} else {
// Need input.
return true;
}
}
// Note: This depends on ReadAhead[Async] setting input[inputEnd] = '\n'
while (input[inputIndex] != (byte) '\n')
inputIndex++;View on GitHub (pinned to 9d3859a785)