jstedfast/MailKit · critical · ImapProtocolException

The IMAP server has unexpectedly disconnected.

Error message

The IMAP server has unexpectedly disconnected.

What it means

MailKit throws this ImapProtocolException from ImapStream.ReadAhead when reading from the socket returns 0 bytes or otherwise fails mid-command, meaning the TCP connection to the IMAP server dropped without a proper BYE response. Setting IsConnected=false, the ImapClient transitions to a disconnected state and the in-flight command fails.

Solutions

  1. Reconnect: create/reconnect the ImapClient, re-authenticate, and re-select the folder, then retry the operation
  2. Wrap long-running sessions with periodic NOOP keepalive (ImapClient's KeepAlive) to defeat idle timeouts
  3. Implement retry logic that detects ImapProtocolException/ServiceNotConnected and rebuilds the connection
  4. Check server logs and network path (NAT idle timeout, LB settings) if drops are frequent

Example fix

// before
var messages = folder.Fetch (0, -1, summary);
// after
try {
    var messages = folder.Fetch (0, -1, summary);
} catch (ImapProtocolException) {
    client.Disconnect (true);
    client.Connect (host, port, useSsl);
    client.Authenticate (user, pass);
    folder = client.GetFolder (folderName);
    folder.Open (FolderAccess.ReadOnly);
    var messages = folder.Fetch (0, -1, summary);
}
Defensive patterns

Strategy: retry

Validate before calling

if (!client.IsConnected) { await ReconnectAsync (); }

Try / catch

try { return await folder.FetchAsync (0, -1, summary); } catch (ImapProtocolException ex) { await ReconnectAsync (); return await folder.FetchAsync (0, -1, summary); }

Prevention

When it happens

Trigger: Server process crash/restart, idle connection killed by a NAT/firewall/load balancer, network outage, or server closing the connection during any read (ReadLine, token parsing, literal reads).

Common situations: Long-lived connections with NOOP keepalives disabled hitting idle timeouts; server maintenance windows; flaky mobile/VPN networks; reading a large message fetch when the server dies mid-literal.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


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

Appendix: source

Thrown at MailKit/Net/Imap/ImapStream.cs:321

		int ReadAhead (int atleast, CancellationToken cancellationToken)
		{
			if (!AlignReadAheadBuffer (atleast, out int left, out int start, out int end))
				return left;

			try {
				var network = Stream as NetworkStream;
				int nread;

				cancellationToken.ThrowIfCancellationRequested ();

				network?.Poll (SelectMode.SelectRead, cancellationToken);

				if ((nread = Stream.Read (input, start, end - start)) > 0) {
					logger.LogServer (input, start, nread);
					inputEnd += nread;
				} else {
					throw new ImapProtocolException ("The IMAP server has unexpectedly disconnected.");
				}

				if (network == null)
					cancellationToken.ThrowIfCancellationRequested ();
			} catch {
				IsConnected = false;
				throw;
			}

			return inputEnd - inputIndex;
		}

		async ValueTask<int> ReadAheadAsync (int atleast, CancellationToken cancellationToken)
		{
			if (!AlignReadAheadBuffer (atleast, out int left, out int start, out int end))
				return left;

			try {

View on GitHub (pinned to 9d3859a785)