Repository navigation
Send one LMTP DATA reply per recipient (RFC 2033 4.2) - #648
Draft
aiolibsbot wants to merge 1 commit into
Draft
aiolibsbot wants to merge 1 commit into
aiolibsbot wants to merge 1 commit into
Conversation
LMTP requires the server to answer DATA once for every recipient that a RCPT command accepted, in order, because delivery is per-mailbox and can succeed for one recipient while failing for another. aiosmtpd sent a single reply, desynchronising conformant LMTP clients. smtp_DATA now maps the DATA hook's return value through an overridable _data_replies() seam, evaluated while the envelope is still intact. SMTP keeps its single reply; LMTP repeats the status once per recipient, or uses a per-recipient list if handle_DATA returns one. Closes aio-libs#517
This branch has not been deployed
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.
What
LMTPnow sends oneDATAreply per accepted recipient, as RFC 2033 § 4.2 requires, instead of a single reply for the whole message.Why
LMTP exists precisely because delivery is per-mailbox: it can succeed for one recipient and fail for another, so the protocol mandates one reply per
RCPTthat was accepted, in order. aiosmtpd sent exactly one — a conformant LMTP client (Postfix's, Mailman's) reads the first reply and then finds the remaining ones sitting in the stream, desynchronising the session. Closes #517.How
smtp_DATA()no longer pushes the terminal reply itself; it maps theDATAhook's return value through a new overridableSMTP._data_replies()seam and pushes whatever comes back. The seam is evaluated before the post-DATA state reset, so it can still seeenvelope.rcpt_tos.SMTP._data_replies()— unchanged behaviour: a one-element list.LMTP._data_replies()— repeats a single status once per recipient, or accepts a list/tuple of per-recipient statuses fromhandle_DATAso a handler can report each mailbox's real outcome. A length mismatch raisesValueError, which the session surfaces as a500rather than silently misattributing statuses.No new constructor flag: LMTP was simply non-conformant here, and no existing handler can have depended on the truncated reply stream.
Testing
5 new tests in
test_lmtp.pycovering: two recipients → two replies; one recipient → one reply and a session still usable afterwards; a single status repeated; per-recipient statuses delivered inRCPTorder; and the count-mismatch error path. Full suite: 560 passed.flake8clean,mypyadds no new errors, and the sphinx HTML build is warning-free for the touched pages.Quality Report
Changes: 6 files changed, 177 insertions(+), 7 deletions(-)
Code scan: clean
Tests: skipped
Branch hygiene: clean
Generated by Kōan