Opened 4 hours ago
Last modified 4 hours ago
#36746 assigned Bug
IndexError in prep_address() when parsing invalid email addresses like 'to@'
| Reported by: | Mahdi Dehghan | Owned by: | Mahdi Dehghan |
|---|---|---|---|
| Component: | Core (Mail) | Version: | dev |
| Severity: | Normal | Keywords: | |
| Cc: | Mahdi Dehghan | Triage Stage: | Unreviewed |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
When parsing invalid email addresses (such as 'to@') in the SMTP backend's prep_address() method, Python's email parser raises an IndexError instead of the expected ValueError. This causes the test test_avoids_sending_to_invalid_addresses to fail.
Steps to reproduce:
- Run Django's test suite:
./runtests.py mail.tests.SMTPBackendTests.test_avoids_sending_to_invalid_addresses - The test fails with IndexError when trying to parse 'to@'
Root cause:
The prep_address() method at line 172 in django/core/mail/backends/smtp.py directly calls AddressHeader.value_parser(address) without exception handling. When parsing malformed addresses like 'to@', Python's email parser first raises HeaderParseError, then during exception handling attempts to parse the address differently, which leads to an IndexError when trying to access value[0] on an empty string.
Proposed solution:
Wrap the AddressHeader.value_parser() call in a try-except block to catch HeaderParseError, IndexError, and ValueError exceptions, converting them to ValueError with an appropriate message. This matches the pattern already used in the deprecated sanitize_address() function in django/core/mail/message.py (line 115).
Expected behavior:
The prep_address() method should catch parsing exceptions and raise ValueError with message "Invalid address" for invalid addresses, matching the test's expectation.
Actual behavior:
IndexError: string index out of range is raised from Python's email._header_value_parser when parsing addresses like 'to@'.
Error traceback:
ERROR: test_avoids_sending_to_invalid_addresses (mail.tests.SMTPBackendTests.test_avoids_sending_to_invalid_addresses) [<object object at 0x12d0aff70>] (email_address='to@')
Verify invalid addresses can't sneak into SMTP commands through
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/email/_header_value_parser.py", line 1965, in get_address
token, value = get_group(value)
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/email/_header_value_parser.py", line 1923, in get_group
raise errors.HeaderParseError("expected ':' at end of group "
email.errors.HeaderParseError: expected ':' at end of group display name but found '@'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/email/_header_value_parser.py", line 1791, in get_mailbox
token, value = get_name_addr(value)
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/email/_header_value_parser.py", line 1777, in get_name_addr
token, value = get_angle_addr(value)
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/email/_header_value_parser.py", line 1702, in get_angle_addr
raise errors.HeaderParseError(
email.errors.HeaderParseError: expected angle-addr but found '@'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/unittest/case.py", line 58, in testPartExecutor
yield
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/unittest/case.py", line 539, in subTest
yield
File "tests/mail/tests.py", line 3070, in test_avoids_sending_to_invalid_addresses
backend.send_messages([email])
File "django/core/mail/backends/smtp.py", line 138, in send_messages
sent = self._send(message)
File "django/core/mail/backends/smtp.py", line 151, in _send
recipients = [self.prep_address(addr) for addr in email_message.recipients()]
File "django/core/mail/backends/smtp.py", line 172, in prep_address
parsed = AddressHeader.value_parser(address)
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/email/headerregistry.py", line 333, in value_parser
address_list, value = parser.get_address_list(value)
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/email/_header_value_parser.py", line 1988, in get_address_list
token, value = get_address(value)
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/email/_header_value_parser.py", line 1968, in get_address
token, value = get_mailbox(value)
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/email/_header_value_parser.py", line 1794, in get_mailbox
token, value = get_addr_spec(value)
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/email/_header_value_parser.py", line 1647, in get_addr_spec
token, value = get_domain(value[1:])
File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/email/_header_value_parser.py", line 1604, in get_domain
if value[0] in CFWS_LEADER:
IndexError: string index out of range
Change History (3)
comment:2 by , 4 hours ago
| Owner: | set to |
|---|---|
| Status: | new → assigned |