fix: send the SMTP greeting line and its CRLF in a single write#3599
Open
flowww-cicd wants to merge 1 commit into
Open
fix: send the SMTP greeting line and its CRLF in a single write#3599flowww-cicd wants to merge 1 commit into
flowww-cicd wants to merge 1 commit into
Conversation
The initial 220 greeting was emitted with IO#print, which writes the string
and then the $\ output record separator ("\r\n", set in prepare_environment)
as two separate writes. These can leave the socket as two TCP segments: the
greeting text, then a delayed CRLF.
Strict clients that read the greeting text before its CRLF arrives may issue
EHLO early; the trailing CRLF then arrives prepended to the EHLO reply and
breaks their line parsing (observed: the client waits for a "complete" reply
and hangs until timeout, never issuing STARTTLS/AUTH). TCP is a byte stream
(RFC 5321 2.1), so this is legal server behaviour, but writing the greeting
line atomically (matching how all other responses are written) avoids
tripping such clients.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The initial
220greeting is emitted withIO#print, which writes the greeting string and then the$\output record separator ("\r\n", set inprepare_environment) as two separate writes. On the wire these can be flushed as two TCP segments: the greeting text, then a delayed CRLF.Impact
Strict clients that read the greeting text before its CRLF arrives may issue
EHLOearly; the trailing CRLF then arrives prepended to theEHLOreply and breaks their line parsing. Observed in production with Persits AspEmail.NET: the client keeps waiting for a "complete" greeting line, hangs until timeout, and never issuesSTARTTLS/AUTH— so no mail is ever sent.TCP is a byte stream (RFC 5321 §2.1), so splitting a response across segments is legal server behaviour and such clients are arguably at fault. But every other response in the SMTP server is already written as a single line; making the greeting consistent (one atomic write, CRLF included) sidesteps the issue at zero cost.
Change
app/lib/smtp_server/server.rb: replacenew_io.print("220 … ESMTP Postal/#{client.trace_id}")(string +$\) withnew_io.write("220 … ESMTP Postal/#{client.trace_id}\r\n").The bytes on the wire are identical (the previous
printappended the same"\r\n"via$\); they are now guaranteed to be written together. No behaviour change for compliant clients, so existing specs are unaffected.