Skip to content

fix(smtp-server): treat TLS read disconnects as client-gone, not errors#3604

Open
kiku98 wants to merge 1 commit into
postalserver:mainfrom
kiku98:fix/smtp-tls-read-eof-noise
Open

fix(smtp-server): treat TLS read disconnects as client-gone, not errors#3604
kiku98 wants to merge 1 commit into
postalserver:mainfrom
kiku98:fix/smtp-tls-read-eof-noise

Conversation

@kiku98

@kiku98 kiku98 commented Jul 14, 2026

Copy link
Copy Markdown

Problem

When a client disconnects abruptly, OpenSSL and the socket layer raise errors that the SMTP server's event loop logged as genuine server errors — with a full backtrace and a Sentry report — despite being routine client-gone events (port scanners, load-balancer health checks, senders whose connection drops).

Three paths in run_event_loop were affected, each falling through to the generic rescue StandardError:

  • Handshake path — a client resetting the connection mid SSL_accept raises Errno::ECONNRESET (not an SSLError), which the handshake rescue did not handle.
  • Read path — an abrupt disconnect while reading on a TLS socket raises OpenSSL::SSL::SSLError (SSL_read: unexpected eof while reading) rather than an EOFError. The read rescue only handled EOFError, Errno::ECONNRESET and Errno::ETIMEDOUT, so these fell through.
  • Write path — a client gone before the response is written raises Errno::EPIPE ("broken pipe") in addition to the already-handled Errno::ECONNRESET.

Fix

Extend each rescue so an abrupt disconnect on any path is treated the same as a plain-socket EOF (eof = true) — the connection is closed quietly instead of being reported as a server error:

  • Handshake rescue: add Errno::ECONNRESET, Errno::ETIMEDOUT
  • Read rescue: add OpenSSL::SSL::SSLError
  • Write rescue: add Errno::EPIPE

No behaviour change for successful connections.

…rors

When a client disconnects abruptly, OpenSSL and the socket layer raise
errors that the SMTP server logged as genuine server errors (with a full
backtrace and Sentry report) despite being routine client-gone events -
commonly caused by port scanners, load-balancer health checks and
senders whose connection drops.

Three paths in the event loop were affected:

  - Handshake path: a client resetting the connection mid SSL_accept
    raises Errno::ECONNRESET (not an SSLError), which the handshake
    rescue did not handle.

  - Read path: an abrupt disconnect while reading raises
    OpenSSL::SSL::SSLError ("SSL_read: unexpected eof while reading")
    rather than an EOFError, which the read rescue did not handle.

  - Write path: a client gone before the response is written raises
    Errno::EPIPE ("broken pipe") as well as the already-handled
    Errno::ECONNRESET.

Extend each rescue so an abrupt disconnect on any path is treated the
same as a plain EOF: the connection is closed quietly instead of being
reported as a server error.
@kiku98
kiku98 force-pushed the fix/smtp-tls-read-eof-noise branch from b3e1c2c to 38636f8 Compare July 14, 2026 16:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants