From 855af6076518013f5c6d0c887a3765184215100e Mon Sep 17 00:00:00 2001 From: Phantom-d-e-v <82759425+Phantom-d-e-v@users.noreply.github.com> Date: Fri, 10 Jul 2026 23:25:29 +0000 Subject: [PATCH 1/3] gh-130110: Support hyphens in RFC 2231 continuation parameter names Parameter names containing hyphens (e.g. `file-name*0*`) were not recognized as RFC 2231 continuations because the matching regular expression only allowed `\w+`. As a result, such parameters were left undecoded by `email.utils.decode_params`. Adjust the regular expression to also accept hyphens (`[\w-]+`), which matches the production behaviour for non-hyphenated names. Fixes: gh-130110 --- Lib/email/utils.py | 2 +- Lib/test/test_email/test_email.py | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Lib/email/utils.py b/Lib/email/utils.py index 6889c5591bf030..a8216a62765e65 100644 --- a/Lib/email/utils.py +++ b/Lib/email/utils.py @@ -399,7 +399,7 @@ def encode_rfc2231(s, charset=None, language=None): return "%s'%s'%s" % (charset, language, s) -rfc2231_continuation = re.compile(r'^(?P\w+)\*((?P[0-9]+)\*?)?$', +rfc2231_continuation = re.compile(r'^(?P[\w-]+)\*((?P[0-9]+)\*?)?$', re.ASCII) def decode_params(params): diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py index e40c82bba9af42..6d66238b885946 100644 --- a/Lib/test/test_email/test_email.py +++ b/Lib/test/test_email/test_email.py @@ -400,6 +400,18 @@ def test_continuation_sorting_part_order(self): filename = msg.get_filename() self.assertEqual(filename, 'foo bar.txt') + def test_continuation_with_hyphenated_name(self): + # gh-130110: parameter names containing hyphens were not recognized + # as RFC 2231 continuations and were left undecoded. + msg = email.message_from_string( + "Content-Disposition: attachment; " + "file-name*0*=\"utf-8''start\"; " + "file-name*1*=\"-middle-\"; " + "file-name*2*=\"end\"\n" + ) + value = msg.get_param('file-name', header='content-disposition') + self.assertEqual(value, ('utf-8', '', 'start-middle-end')) + def test_sorting_no_continuations(self): msg = email.message_from_string( "Content-Disposition: attachment; " From 5fa95ba1beebc1cf684281cc2dc38283a633fc31 Mon Sep 17 00:00:00 2001 From: Phantom-d-e-v <82759425+Phantom-d-e-v@users.noreply.github.com> Date: Fri, 10 Jul 2026 23:32:59 +0000 Subject: [PATCH 2/3] Add NEWS entry for gh-130110 --- .../Library/2026-07-10-23-32-52.gh-issue-130110.R7xQz2.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-07-10-23-32-52.gh-issue-130110.R7xQz2.rst diff --git a/Misc/NEWS.d/next/Library/2026-07-10-23-32-52.gh-issue-130110.R7xQz2.rst b/Misc/NEWS.d/next/Library/2026-07-10-23-32-52.gh-issue-130110.R7xQz2.rst new file mode 100644 index 00000000000000..f80f0bdf8b3893 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-10-23-32-52.gh-issue-130110.R7xQz2.rst @@ -0,0 +1,3 @@ +:meth:`email.utils.decode_params` (and the parameter parsing it backs) now +correctly decodes :rfc:`2231` continuation parameter names that contain +hyphens, such as ``file-name*0*``. From 9c79827984e12656a6ec8268bc14324af0bc3f4f Mon Sep 17 00:00:00 2001 From: Phantom-d-e-v <82759425+Phantom-d-e-v@users.noreply.github.com> Date: Sat, 11 Jul 2026 22:34:23 +0000 Subject: [PATCH 3/3] gh-130110: allow hyphens in RFC 2231 continuation parameter names decode_params() matches RFC 2231 continuation parameter names with the regex r'^(?P\w+)\*...'. That rejects names containing a hyphen (e.g. `file-name*0*`), leaving such continuations undecoded. Widen the name class to [\w-] so hyphenated names are recognized, while still restricting to RFC 2045 `token` characters: under re.ASCII, \w is [A-Za-z0-9_], all of which are valid token chars, so no invalid character can match. Co-Authored-By: Hermes Agent --- Lib/email/utils.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Lib/email/utils.py b/Lib/email/utils.py index a8216a62765e65..001b1dd4081edf 100644 --- a/Lib/email/utils.py +++ b/Lib/email/utils.py @@ -401,6 +401,12 @@ def encode_rfc2231(s, charset=None, language=None): rfc2231_continuation = re.compile(r'^(?P[\w-]+)\*((?P[0-9]+)\*?)?$', re.ASCII) +# `\w` is ASCII-only here (re.ASCII), so it matches exactly [A-Za-z0-9_], +# all of which are valid RFC 2045 `token` characters. Adding `-` lets the +# regex recognize hyphenated continuation parameter names (e.g. `file-name*0*`). +# This is intentionally stricter than the full RFC 2045 `token` set (which +# also permits e.g. `.`, `!`, `#`); none of those appear in practice for +# RFC 2231 parameter names, and broadening the class is out of scope here. def decode_params(params): """Decode parameters list according to RFC 2231.