jstedfast/MailKit · error · TimeoutException
Operation timed out after
Error message
Operation timed out after {writeTimeout} milliseconds What it means
NetworkStream.WriteAsync mirrors the read path: if the socket send doesn't complete within writeTimeout, the stream disconnects and throws a TimeoutException with the writeTimeout in the message. This indicates the server stopped consuming data (or the network is stalled) while MailKit was writing a command or payload.
Solutions
- Increase the client's Timeout property to accommodate slow upstream bandwidth for the payload size.
- Catch TimeoutException, reconnect, and resume/retry the send (MailKit has already disconnected the stream).
- Check TCP stack/network health (half-open connections, MTU issues) and server read-back pressure.
Example fix
// before smtp.Timeout = 10_000; await smtp.SendAsync(message); // large attachment, slow uplink // after smtp.Timeout = 300_000; // allow 5 min for large uploads await smtp.SendAsync(message);
Defensive patterns
Strategy: try-catch
Try / catch
try { await smtp.SendAsync(message); }
catch (TimeoutException) {
await ReconnectAsync(); // stream was disconnected mid-write
await smtp.SendAsync(message);
} Prevention
- Scale Timeout with payload size / expected upstream bandwidth
- Avoid half-open dead sockets by keeping the client's Timeout below OS TCP keepalive hangs
- Retry large sends from a fresh connection
When it happens
Trigger: Writing large payloads (e.g. SMTP message body, APPEND data) over a stalled connection, or any command write that exceeds the client's Timeout; the AcceptProxyConnection path writing the proxy request when the backend isn't reading.
Common situations: Uploading large messages on slow/upstream-limited links with a small Timeout; server stuck and not reading the socket; dead peers kept alive by half-open TCP connections.
Understand the failure class
Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Operation timed out after
- The POP3 server has unexpectedly disconnected.
- Specified argument was out of the range of valid values…
- The ImapClient is not connected.
- The IMAP server has unexpectedly disconnected.
AI-assisted analysis of jstedfast/MailKit@9d3859a785 (2026-09-15).
Data as JSON: /api/errors/060b877cffb82532.
Report an issue: GitHub.
Appendix: source
Thrown at MailKit/Net/NetworkStream.cs:238
// Capture the WriteTimeout so even if we get an exception and disconnect the socket, we still have it.
int writeTimeout = WriteTimeout;
using (var timeout = new CancellationTokenSource (writeTimeout)) {
using (var linked = CancellationTokenSource.CreateLinkedTokenSource (cancellationToken, timeout.Token)) {
using (var registration = linked.Token.Register (() => tcs.TrySetCanceled (), false)) {
send!.SetBuffer (buffer, offset, count);
send.UserToken = tcs;
if (!Socket.SendAsync (send))
AsyncOperationCompleted (null, send);
try {
await tcs.Task.ConfigureAwait (false);
} catch (OperationCanceledException ex) {
Disconnect ();
if (timeout.IsCancellationRequested)
throw new TimeoutException ($"Operation timed out after {writeTimeout} milliseconds", ex);
throw;
} catch (Exception ex) {
Disconnect ();
if (ex is SocketException)
throw new IOException (ex.Message, ex);
throw;
}
}
}
}
}
public override void Flush ()
{
}
public override Task FlushAsync (CancellationToken cancellationToken)
{View on GitHub (pinned to 9d3859a785)