Repository navigation
Conversation
partition_email() read the body from the single part that EmailMessage.get_body() returns. Apple Mail sends a message with a file placed inside its text as a multipart/mixed part holding an HTML part, the file, and another HTML part, so with the default content_source="text/html" everything after the file was lost. A mailing-list footer sent as a part of its own was lost the same way. When the body part is shown by a multipart/mixed part, each inline text, alternative or related part of it now contributes its body, in order. iter_attachments() passes over only the first body-like part of each kind, so an attachment that is, or holds, a part read as body text is skipped; a body with a second multipart/alternative part therefore no longer raises KeyError.
…body # Conflicts: # CHANGELOG.md # unstructured/__version__.py
…body main released 0.27.18; this entry moves to 0.27.19-dev0.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
partition_email()reads the message body from the one partEmailMessage.get_body()returns. When the text of a message is spread over several parts of amultipart/mixed, everything after the first of them never reaches the elements. With the defaultcontent_source="text/html", that includes a common case: Apple Mail sends a message with a file placed inside its text asget_body(preferencelist=("html", "plain"))returns the firsttext/htmlpart, so the text after the file is lost.Four layouts through
partition_email()onmain, with an inline file between the parts where there is one:mainreturnsHere is the report.mixed[html, file, html]mixed[related[html, image], file, html]mixed[alternative[plain, html], plain](a mailing-list footer part)A fifth,
mixed[alternative, alternative], raisesKeyError: 'multipart/alternative'onmain.iter_attachments()hands over the second alternative as an attachment, andget_content()has no handler formultipart/*.Change
unstructured/partition/email.py:EmailPartitioningContext.body_parts, next to.body_part: the parts that together carry the message text, in order. It is[body_part]unlessbody_partis shown by amultipart/mixedpart, as a direct part of it or inside one throughmultipart/alternativeandmultipart/relatedparts only. Then each part of thatmultipart/mixedthatiter_attachments()would take for body text (text/plain,text/html,multipart/alternative,multipart/related) contributespart.get_body(preferencelist). That skips attached files and non-text inline parts, sinceget_body()returnsNonefor them._iter_email_body_elements()partitions each of those parts, as it did the single one.iter_attachments()passes over only the first body-like part of each kind, so a secondtext/htmlpart, or a secondmultipart/alternativepart, arrives there too. That second alternative is what raised theKeyError.content_source="text/plain"is unchanged for the Apple Mail layout: the plain part is not inside themultipart/mixed, and it already carries the whole text.A nested
multipart/mixedpart is not one of those body kinds, so it is left to the attachment loop as before. That is also the case #4424 handles, so the two changes do not read a part twice.CHANGELOG.mdhas a0.27.9-dev0entry, and__version__.pyis bumped to match.Testing
In
test_unstructured/partition/test_email.py, with a new fixtureexample-docs/eml/mime-html-split-by-inline-attachment.eml(the layout above, written for this test):test_partition_email_reads_an_html_body_split_by_an_inline_attachmenttest_partition_email_reads_every_inline_part_of_a_mixed_body: HTML parts, a related part followed by an HTML part, and a footer part.test_partition_email_does_not_partition_a_body_part_again_as_an_attachment: withauto.partitionmocked, a second HTML part is not handed to it as an attachment, while the inline CSV still is. With two alternative parts, nothing is handed over and nothing raises..body_parts: a body in one part, the split fixture,content_source="text/plain", and a message with no body.Results:
test_email.py: 82 passed. Againstmain'semail.py, the 10 new tests fail: the 6 behaviour tests on their assertions, or with theKeyErrorin the two-alternatives case, and the 4 unit tests because.body_partsis new..emlinexample-docs/eml, 40 files, partitioned with both content sources: all 80 outputs are identical tomain's except for the new fixture.body_partalone;multipart/mixed;multipart/mixed;multipart/mixedpart, which the tests do not build: onmainit reachesget_content()in the attachment loop and raises theKeyErrorfix: partition_email raises KeyError on a multipart/* attachment #4424 fixes.ruff checkandruff format --check(0.15.10, the locked version) are clean on both files.CHANGELOG.mdand__version__.pyagree on0.27.9-dev0. I could not runmake check-versionitself, because it needs GNU sed ≥ 4.3.test_auto.pyneeds thepdfextra to import, which is not installed here. Its email cases usefake-email.emlandfake-email-attachment.eml, and both are part of the 80 identical outputs above.To try it: