jstedfast/MailKit · error · SmtpProtocolException

The SMTP server has unexpectedly disconnected.

Error message

The SMTP server has unexpectedly disconnected.

What it means

Same family as [493]: ReadAhead throws SmtpProtocolException 'The SMTP server has unexpectedly disconnected.' when the server closes the connection with no partial response buffered (lastResponse is null). The connection reached EOF before any reply data arrived.

Solutions

  1. Reconnect and retry the operation; the SmtpClient marks the session dead (IsConnected=false)
  2. Use fresh connections per burst of work or implement keepalive/NOOP pinging
  3. Check server and firewall timeout settings versus your connection idle time

Example fix

// before
client.Send(message);
// after
if (!client.IsConnected) { client.Connect(host, port, useSsl); client.Authenticate(user, pass); }
try { client.Send(message); }
catch (SmtpProtocolException) { /* reconnect and retry */ }
Defensive patterns

Strategy: retry

Validate before calling

if (!client.IsConnected) { client.Connect(host, port, useSsl); client.Authenticate(user, pass); }

Try / catch

try { client.Send(message); }
catch (SmtpProtocolException) { client.Dispose(); client = CreateConnectedClient(); /* retry */ }

Prevention

When it happens

Trigger: Server closes the socket before completing a response; connection dropped between sending a command and reading the reply; server process killed mid-exchange.

Common situations: Idle connection reaped by server or NAT/firewall; server restarted; sending on a connection the server already closed after a previous 421.

Related errors


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

Appendix: source

Thrown at MailKit/Net/Smtp/SmtpStream.cs:255

			try {
				var network = Stream as NetworkStream;

				cancellationToken.ThrowIfCancellationRequested ();

				network?.Poll (SelectMode.SelectRead, cancellationToken);
				int nread = Stream.Read (input, offset, count);

				if (nread > 0) {
					logger.LogServer (input, offset, nread);
					inputEnd += nread;

					// Optimization hack used by ReadResponse
					input[inputEnd] = (byte) '\n';
				} else if (lastResponse is not null) {
					throw new SmtpProtocolException ($"The SMTP server has unexpectedly disconnected: {lastResponse}");
				} else {
					throw new SmtpProtocolException ("The SMTP server has unexpectedly disconnected.");
				}
			} catch {
				IsConnected = false;
				throw;
			}

			return inputEnd - inputIndex;
		}

		async Task<int> ReadAheadAsync (CancellationToken cancellationToken)
		{
			AlignReadAheadBuffer (out int offset, out int count);

			try {
				cancellationToken.ThrowIfCancellationRequested ();

				int nread = await Stream.ReadAsync (input, offset, count, cancellationToken).ConfigureAwait (false);

View on GitHub (pinned to 9d3859a785)