Skip to content

gh-145552: smtplib: quoteaddr() returns malformed address for input '<'#145553

Open
stefanzetzsche wants to merge 10 commits intopython:mainfrom
stefanzetzsche:fix/smtplib_quoteaddr_malformed
Open

gh-145552: smtplib: quoteaddr() returns malformed address for input '<'#145553
stefanzetzsche wants to merge 10 commits intopython:mainfrom
stefanzetzsche:fix/smtplib_quoteaddr_malformed

Conversation

@stefanzetzsche
Copy link
Copy Markdown
Contributor

@stefanzetzsche stefanzetzsche commented Mar 5, 2026

Problem

quoteaddr() formats addresses for SMTP MAIL FROM: and RCPT TO: commands, which require angle-bracket format (<addr>). It first tries email.utils.parseaddr(); when that fails (for inputs like '<', '< ', '@'), a fallback path checks if the input starts with < and returns it verbatim — without verifying it also ends with >.

The startswith('<') check was introduced in 4c14bba as part of #51733. Before that commit, unparseable input was unconditionally wrapped in <>.

Reproducer

from smtplib import quoteaddr
print(repr(quoteaddr('<')))   # '<' — missing closing >

Why not unconditional wrapping?

Simply removing the startswith('<') branch and always wrapping with "<%s>" would break the null sender <>, which is a valid SMTP construct (RFC 5321 bounce path). parseaddr('<>') returns ('', '') — a parse failure — so unconditional wrapping would produce <<>>, which is malformed. The startswith('<') check exists specifically to preserve already-bracketed input that parseaddr can't handle.

Fix

Keep the startswith('<') check but add an endswith('>') guard. Already-bracketed input (like <>) passes through; half-open input (like <) falls through to unconditional wrapping:

if addrstring.strip().startswith('<'):
    if addrstring.strip().endswith('>'):
        return addrstring
return "<%s>" % addrstring

stefanzetzsche and others added 2 commits March 5, 2026 15:03
Input starting with '<' but missing closing '>' was returned verbatim.
Ensure the result always ends with '>'.
Add testQuoteAddr for basic quoteaddr behavior and
testQuoteAddrMalformedAngleBracket for inputs starting with '<'
but missing closing '>'. The latter fails without the fix.
@bedevere-app
Copy link
Copy Markdown

bedevere-app Bot commented Mar 5, 2026

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@python-cla-bot
Copy link
Copy Markdown

python-cla-bot Bot commented Mar 5, 2026

All commit authors signed the Contributor License Agreement.

CLA signed

@stefanzetzsche stefanzetzsche marked this pull request as ready for review March 5, 2026 15:20
@stefanzetzsche stefanzetzsche requested a review from a team as a code owner March 5, 2026 15:20
@stefanzetzsche
Copy link
Copy Markdown
Contributor Author

@bitdancer

Comment thread Lib/smtplib.py
# parseaddr couldn't parse it, wrap it in angle brackets.
if addrstring.strip().startswith('<'):
return addrstring
if addrstring.strip().endswith('>'):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay in responding.

I'd prefer to do addrstring.strip() == '<>', which theoretically matches the old behavior. (I say theoretically because the code the old version of this code was calling has moved on as well and I don't feel like going down that rabbit hole.) In any case, it should be correct: only <> is a special case per RFC 5321; we otherwise don't want to do more to fix user errors than to ensure that the provided originator address is sorrounded by the angle quotes.

@bedevere-app
Copy link
Copy Markdown

bedevere-app Bot commented Mar 31, 2026

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

And if you don't make the requested changes, you will be put in the comfy chair!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants