From bfc11a545b9046662e0bbc7fe079b152fe1c618e Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Tue, 21 Jan 2025 10:38:21 -0800 Subject: [PATCH] Change: use simpler method for attaching files (#8845) --- src/documents/mail.py | 41 +++--------- .../tests/samples/eml_with_umlaut.eml | 63 +++++++++++++++++++ src/documents/tests/test_workflows.py | 21 ++++++- 3 files changed, 91 insertions(+), 34 deletions(-) create mode 100644 src/documents/tests/samples/eml_with_umlaut.eml diff --git a/src/documents/mail.py b/src/documents/mail.py index 5183b1bae..12a1c0aa0 100644 --- a/src/documents/mail.py +++ b/src/documents/mail.py @@ -1,7 +1,5 @@ -from email.encoders import encode_base64 -from email.mime.base import MIMEBase +from email import message_from_bytes from pathlib import Path -from urllib.parse import quote from django.conf import settings from django.core.mail import EmailMessage @@ -27,35 +25,14 @@ def send_email( if attachment: # Something could be renaming the file concurrently so it can't be attached with FileLock(settings.MEDIA_LOCK), attachment.open("rb") as f: - file_content = f.read() + content = f.read() + if attachment_mime_type == "message/rfc822": + # See https://forum.djangoproject.com/t/using-emailmessage-with-an-attached-email-file-crashes-due-to-non-ascii/37981 + content = message_from_bytes(f.read()) - main_type, sub_type = ( - attachment_mime_type.split("/", 1) - if attachment_mime_type - else ("application", "octet-stream") + email.attach( + filename=attachment.name, + content=content, + mimetype=attachment_mime_type, ) - mime_part = MIMEBase(main_type, sub_type) - mime_part.set_payload(file_content) - - encode_base64(mime_part) - - # see https://github.com/stumpylog/tika-client/blob/f65a2b792fc3cf15b9b119501bba9bddfac15fcc/src/tika_client/_base.py#L46-L57 - try: - attachment.name.encode("ascii") - except UnicodeEncodeError: - filename_safed = attachment.name.encode("ascii", "ignore").decode( - "ascii", - ) - filepath_quoted = quote(attachment.name, encoding="utf-8") - mime_part.add_header( - "Content-Disposition", - f"attachment; filename={filename_safed}; filename*=UTF-8''{filepath_quoted}", - ) - else: - mime_part.add_header( - "Content-Disposition", - f"attachment; filename={attachment.name}", - ) - - email.attach(mime_part) return email.send() diff --git a/src/documents/tests/samples/eml_with_umlaut.eml b/src/documents/tests/samples/eml_with_umlaut.eml new file mode 100644 index 000000000..5a23cb1c0 --- /dev/null +++ b/src/documents/tests/samples/eml_with_umlaut.eml @@ -0,0 +1,63 @@ +From: =?UTF-8?Q?My_Name=C3=B6er?= +Return-Path: +X-Original-To: rechnung@domain.de +Delivered-To: rechnung@domain.de +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=domainb.de; s=default; + t=1736973836; bh=bCUrrHd7c5mrvMbK20=; + h=Date:To:From:Subject:From; + b=QPaQKuzx2adfCr0S18KVgA5x01KXZknaaEpQW49Ock2ghScLAvv3ij8xfzUbZewCT + CuUAYBmCxbN5ygIztJXfgWpl1Cx5FsVQNpdZ/6Ns= +Received: by mail.domain.de (Postfix, from userid 121) + id 407BCE078A; Wed, 15 Jan 2025 21:43:56 +0100 (CET) +X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on imail.domain.de +X-Spam-Level: +X-Spam-Status: No, score=-3.0 required=1.7 tests=ALL_TRUSTED,BAYES_00, + DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU autolearn=ham autolearn_force=no + version=4.0.0 +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=domain.de; s=default; + t=1736973835; bh=bCUrrHvn+Hd7c5mrvMbK20=; + h=Date:To:From:Subject:From; + b=AjGxzFALRR0AixC1uRhFuQkb4MoBqju1NInlUzx9w+toniNx3ifgkXpGxiV7+JJsr + Z+jNZxck3D3M05ETYnrGInO+vDlosfFU2WqnZn+E= +Received: from [192.168.8.154] (unknown [1.1.1.1]) + (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) + key-exchange X25519 server-signature ECDSA (prime256v1) server-digest + SHA256) + (No client certificate requested) + (Authenticated sender: myuser) + by mail.domain.de (Postfix) with ESMTPSA id C8BC6DF926 + for ; Wed, 15 Jan 2025 21:43:55 +0100 (CET) +Message-ID: +Date: Wed, 15 Jan 2025 21:43:52 +0100 +MIME-Version: 1.0 +User-Agent: Mozilla Thunderbird +Content-Language: de-DE +To: rechnung@domain.de +Subject: No Umlauts here +Autocrypt: addr=myaddr@domain.de; keydata= + xsDiBEK4/dERBACj7Kn2Skjnyq/Q69FKLSd9WJg/7Ta3aZwWiaizzAnB/avBoN9/NPkVCQbB + jeJ8G/uOtYDCgjmxeBNMVM3DOMTu4QfLnl0BoQz811bxiaPqQ6YLRA4MZrawZwerIOS2oSk2 + FDGKsZvAYCG439QK102XPlSPC7c4/oQ+3fwkeqFpEwCg4XYOfTNzis6CZPgkQqyVrpaYR5kD + /j1HIDd1B75eeCb8ifoyWoWHB+cVHR+kEuMw1FMZt7UQ6Pb5nfQTcpEvrH9BTc0GKmTzj1N3 + ExOPaNaGtsc7FAST+5dYflfL1+WVzsNJWgIp6PoAL1XoCZ6l63/qOrHtnp6l42IO8Rg2lDcc + 25YdfiRSlTWuKvleT/okyc6jHioEA/9bUPbpdmUyR5kWRkdRBTjjCipl+o8rSlparnnk+7jh + 1cvOHJlNJ/MYP9vcgDGYFIv+38sY4+UuBBoNmSS7yN5yKpT+XIsSgMEvyRPP6lr1GJ76aT2v + dIvcozHdC9g+nu6AlKgywdWW3hq5IjqRqnmVQfUN/1dL/D1ZImclEJoZR80lQ2hyaXN0aWFu + IFZvZWxrZXIgPGN2b2Vsa2VyQGtuZWJiLmRlPsJ3BBMRCAA3AhsjBgsJCAcDAgQVAggDBBYC + AwECHgECF4AWIQQl96acg1HmEUgEtrfRc0hiUBebOwUCXwQmvwAKCRDRc0hiUBebOxeiAJ43 + bk2DCMuEVho3wRUqEyhNk0/mwQCaA60n1eTn+6bs2WXttTVGkBJGadzOwU0EQrj92RAIAKJz + rvwheohL4D327LEpy1AkIjUJotYUt9fPW+MVDSsoyj67HFTRz1WcK51+/8Fi6jedKxmR3hAi + GlZRvpsJ2chOuaynMac0Uv42rnSGHcLZf0KxLG+r7HOPSEAnSrbDAhWbuqyV994vCIfG9LDz + RDocaUEyJ7M+QV4VGS6Z3PPgxm78kCJ5TGHXRA96ponSptkyfIxvKHBa2TyrhMoLj4TmW4CO + SHmQD2e3EVIYlhERdPEQ5DmCljeO19ZopjNOLcAx4eOyguwvjpdeLUQJdaryWo56USWKbrmU + VrK4OodWkgcUvaagvey0MkABZkY0RMRKrfMuGb+Vw2nH9OGaRysAAwYH/AxC/+/m+OTA6tmA + AXd31vpMNUdVoPjyO+FQ7f8mwXa3SjPZeQLvpA1RfYFdDtSfr16RI8s41xtL12IYZr4nyRG/ + wYPmM2WvcTUp3vWVizzHSERlarONc7aaCGXghg6Trpbz7+tv2MOpRLMfJd+6kyCz5pRSGeuX + z0iIxWSny1+Vc9uGgxyjJ21FFuvYPR8xmjfCGXvsnWLhKxTPNdhIG6/im/1/uTznzlfGUvgx + eNuzVphaVSPzP5DBVxJbKZzZYKOydQLx0Z79YF2xCGmz80EsSajpQNMvNYuNQXuH1ogFIP7e + PNOoaoakYuLE1YMhWL+AJzYRRevW8k/VLBgsYvbCRgQYEQIABgUCQrj92QAKCRDRc0hiUBeb + O/HXAJ0WAbB0sQ0SBVF+2Nlabw4HICAiKwCg4Fe9VjcfR4+ZJqq3Mx1c+IAE65c= +Content-Type: text/plain; charset=UTF-8; format=flowed +Content-Transfer-Encoding: 8bit + +But here: üöäüäö diff --git a/src/documents/tests/test_workflows.py b/src/documents/tests/test_workflows.py index cb5a132af..b9205d4bb 100644 --- a/src/documents/tests/test_workflows.py +++ b/src/documents/tests/test_workflows.py @@ -2149,9 +2149,8 @@ class TestWorkflows( EMAIL_ENABLED=True, PAPERLESS_URL="http://localhost:8000", ) - @mock.patch("httpx.post") @mock.patch("django.core.mail.message.EmailMessage.send") - def test_workflow_email_include_file(self, mock_email_send, mock_post): + def test_workflow_email_include_file(self, mock_email_send): """ GIVEN: - Document updated workflow with email action @@ -2199,6 +2198,24 @@ class TestWorkflows( mock_email_send.assert_called_once() + mock_email_send.reset_mock() + # test with .eml file + test_file2 = shutil.copy( + self.SAMPLE_DIR / "eml_with_umlaut.eml", + self.dirs.scratch_dir / "eml_with_umlaut.eml", + ) + + doc2 = Document.objects.create( + title="sample eml", + checksum="123456", + filename=test_file2, + mime_type="message/rfc822", + ) + + run_workflows(WorkflowTrigger.WorkflowTriggerType.DOCUMENT_UPDATED, doc2) + + mock_email_send.assert_called_once() + @override_settings( EMAIL_ENABLED=False, )