https://github.com/python/cpython/commit/4af46b4ab5af49d8df034320a9a70fcbb062f7cf
commit: 4af46b4ab5af49d8df034320a9a70fcbb062f7cf
branch: main
author: Henry Jones <[email protected]>
committer: bitdancer <[email protected]>
date: 2026-04-14T09:10:08-04:00
summary:
gh-148192: Fix Generator._make_boundary behavior with CRLF line endings.
(#148193)
The Generator._make_boundary regex did not match on boundary phrases correctly
when using CRLF line endings due to re.MULTILINE not considering \r\n as a line
ending.
files:
A Misc/NEWS.d/next/Library/2026-04-07-14-13-40.gh-issue-148192.34AUYQ.rst
M Lib/email/generator.py
M Lib/test/test_email/test_generator.py
diff --git a/Lib/email/generator.py b/Lib/email/generator.py
index cebbc416087fee..ba11d63fba600a 100644
--- a/Lib/email/generator.py
+++ b/Lib/email/generator.py
@@ -392,7 +392,7 @@ def _make_boundary(cls, text=None):
b = boundary
counter = 0
while True:
- cre = cls._compile_re('^--' + re.escape(b) + '(--)?$',
re.MULTILINE)
+ cre = cls._compile_re('^--' + re.escape(b) + '(--)?\r?$',
re.MULTILINE)
if not cre.search(text):
break
b = boundary + '.' + str(counter)
diff --git a/Lib/test/test_email/test_generator.py
b/Lib/test/test_email/test_generator.py
index c2d7d09d591e86..3c9a86f3e8cf29 100644
--- a/Lib/test/test_email/test_generator.py
+++ b/Lib/test/test_email/test_generator.py
@@ -1,13 +1,20 @@
import io
import textwrap
import unittest
+import random
+import sys
from email import message_from_string, message_from_bytes
from email.message import EmailMessage
+from email.mime.multipart import MIMEMultipart
+from email.mime.text import MIMEText
from email.generator import Generator, BytesGenerator
+import email.generator
from email.headerregistry import Address
from email import policy
import email.errors
from test.test_email import TestEmailBase, parameterize
+import test.support
+
@parameterize
@@ -288,6 +295,36 @@ def test_keep_long_encoded_newlines(self):
g.flatten(msg)
self.assertEqual(s.getvalue(), self.typ(expected))
+ def _test_boundary_detection(self, linesep):
+ # Generate a boundary token in the same way as _make_boundary
+ token = random.randrange(sys.maxsize)
+
+ def _patch_random_randrange(*args, **kwargs):
+ return token
+
+ with test.support.swap_attr(
+ random, "randrange", _patch_random_randrange
+ ):
+ boundary = self.genclass._make_boundary(text=None)
+ boundary_in_part = (
+ "this goes before the boundary\n--"
+ + boundary
+ + "\nthis goes after\n"
+ )
+ msg = MIMEMultipart()
+ msg.attach(MIMEText(boundary_in_part))
+ self.genclass(self.ioclass()).flatten(msg, linesep=linesep)
+ # Generator checks the message content for the string it is about
+ # to use as a boundary ('token' in this test) and when it finds it
+ # in our attachment appends .0 to make the boundary it uses unique.
+ self.assertEqual(msg.get_boundary(), boundary + ".0")
+
+ def test_lf_boundary_detection(self):
+ self._test_boundary_detection("\n")
+
+ def test_crlf_boundary_detection(self):
+ self._test_boundary_detection("\r\n")
+
class TestGenerator(TestGeneratorBase, TestEmailBase):
diff --git
a/Misc/NEWS.d/next/Library/2026-04-07-14-13-40.gh-issue-148192.34AUYQ.rst
b/Misc/NEWS.d/next/Library/2026-04-07-14-13-40.gh-issue-148192.34AUYQ.rst
new file mode 100644
index 00000000000000..87a568b50c17c3
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-04-07-14-13-40.gh-issue-148192.34AUYQ.rst
@@ -0,0 +1,3 @@
+``email.generator.Generator._make_boundary`` could fail to detect a duplicate
+boundary string if linesep was not \n. It now correctly detects boundary
+strings when linesep is \r\n as well.
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]