https://github.com/python/cpython/commit/bc0ada075c56399131ca34ca6f281e477b7b9f40
commit: bc0ada075c56399131ca34ca6f281e477b7b9f40
branch: 3.15
author: Miss Islington (bot) <[email protected]>
committer: hugovk <[email protected]>
date: 2026-10-23T19:12:53Z
summary:

[3.15] gh-159304: Fix AttributeError in email get_body() for nested malformed 
multipart (GH-159306) (#159492)

Co-authored-by: Julian Prolejko <[email protected]>
Co-authored-by: Hugo van Kemenade <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-10-13-12-00-00.gh-issue-159304.mFbYq2.rst
M Lib/email/message.py
M Lib/test/test_email/test_message.py

diff --git a/Lib/email/message.py b/Lib/email/message.py
index 64e6c1e23cfb47f..093b9012f31666e 100644
--- a/Lib/email/message.py
+++ b/Lib/email/message.py
@@ -1026,7 +1026,7 @@ def _find_body(self, part, preferencelist):
             if subtype in preferencelist:
                 yield (preferencelist.index(subtype), part)
             return
-        if maintype != 'multipart' or not self.is_multipart():
+        if maintype != 'multipart' or not part.is_multipart():
             return
         if subtype != 'related':
             for subpart in part.iter_parts():
diff --git a/Lib/test/test_email/test_message.py 
b/Lib/test/test_email/test_message.py
index 56ad446694d1f88..974b0ceaafbde4e 100644
--- a/Lib/test/test_email/test_message.py
+++ b/Lib/test/test_email/test_message.py
@@ -1081,6 +1081,25 @@ def test_get_body_malformed(self):
         # AttributeError: 'str' object has no attribute 'is_attachment'
         m.get_body()
 
+    def test_get_body_malformed_nested_multipart(self):
+        # gh-159304: a nested multipart part without a boundary has a
+        # string payload, which get_body() must not iterate over.
+        msg = textwrap.dedent("""\
+            From: [email protected]
+            To: [email protected]
+            Subject: Malformed
+            Content-Type: multipart/related; boundary=OUTER
+
+            --OUTER
+            Content-Type: multipart/related
+
+            raw body no boundary
+            --OUTER--
+            """)
+        m = self._str_msg(msg)
+        self.assertIsNone(m.get_body(('plain', 'html')))
+        self.assertIs(m.get_body(('related',)), m)
+
     def test_get_bytes_payload_with_quoted_printable_encoding(self):
         # We use a memoryview to avoid directly changing the private payload
         # and to prevent using the dedicated paths for string or bytes objects.
diff --git 
a/Misc/NEWS.d/next/Library/2026-10-13-12-00-00.gh-issue-159304.mFbYq2.rst 
b/Misc/NEWS.d/next/Library/2026-10-13-12-00-00.gh-issue-159304.mFbYq2.rst
new file mode 100644
index 000000000000000..8f5b61efe039593
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-10-13-12-00-00.gh-issue-159304.mFbYq2.rst
@@ -0,0 +1,2 @@
+Fix :exc:`AttributeError` in :meth:`email.message.EmailMessage.get_body` when a
+nested ``multipart`` part is malformed and its payload is a string.

_______________________________________________
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]

Reply via email to