[FIX] mail: mime type alias

Some printers incorrectly specify the content-type of PDFs as "pdf" instead of
the correct "application/pdf." To handle this situation,
an alias has been introduced, treating content-type "pdf" as "application/pdf."

[Reproducing original bug]
1. run odoo with documents module
2. prepare email file
2.1 create email with a pdf attached
2.2 export email to .eml
2.3 modify content-type of the pdf from "application/pdf" to "pdf"
3. send prepared email to odoo to inbox-financial alias (the default one
   creating documents)
4. Go to documents, observe that the created PDF is blank!

[Motivation for fix]
Since:
1. Odoo uses the Python built-in module for parsing emails*
    (the actual issue lies outside Odoo code).
2. "pdf" is not an accepted MIME type according to current norms
    (https://datatracker.ietf.org/doc/html/rfc6838#section-4.2).
It's not an actual Odoo bug.
However, redirecting this issue to the appropriate printer manufacturer and
waiting for a fix may be time-consuming, hence the proposed fix.

*function parsing email with the Python built-in module
https://github.com/odoo/odoo/blob/407ea60796a2b18eb02f5569e1cfab9f1163a572/addons/mail/models/mail_thread.py#L1282

opw-3462260

closes odoo/odoo#147363

X-original-commit: e95a19341536e442239a7e940089d7f66ab9f534
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
Andrzej(pian)
2023-12-23 15:09:31 +00:00
parent 41b4f14d8b
commit b0067dfd72
3 changed files with 37 additions and 0 deletions
+4
View File
@@ -1523,6 +1523,10 @@ class MailThread(models.AbstractModel):
part.set_charset('utf-8')
encoding = part.get_content_charset() # None if attachment
# Correcting MIME type for PDF files
if part.get('Content-Type', '').startswith('pdf;'):
part.replace_header('Content-Type', 'application/pdf' + part.get('Content-Type', '')[3:])
content = part.get_content()
info = {'encoding': encoding}
# 0) Inline Attachments -> attachments, with a third part in the tuple to match cid / attachment
+20
View File
@@ -1292,3 +1292,23 @@ To: lucie@petitebedaine.fr
From: "Bruce Wayne" <bruce@wayneenterprises.com>
SSBhbSB0aGUgQmF0TWFuCg=="""
MAIL_PDF_MIME_TEMPLATE = """\
To: {to}
From: {email_from}
Subject: {subject}
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="----=_Part_4200734_24778174.1344608186754"
Date: Fri, 10 Aug 2012 14:16:26 +0000
------=_Part_4200734_24778174.1344608186754
Content-Type: {pdf_mime}; name="scan_soraya.lernout_1691652648.pdf"
Content-Transfer-Encoding: base64
JVBERi0xLjEKJcKlwrHDqwoKMSAwIG9iagogIDw8IC9UeXBlIC9DYXRhbG9nCiAgICAgL1BhZ2VzIDIgMCBSCiAgPj4KZW5kb2JqCgoyIDAgb2JqCiAgPDwgL1R5cGUgL1BhZ2VzCiAgICAgL0tpZHMgWzMgMCBSXQogICAgIC9Db3VudCAxCiAgICAgL01lZGlhQm94IFswIDAgMzAwIDE0NF0KICA+PgplbmRvYmoKCjMgMCBvYmoKICA8PCAgL1R5cGUgL1BhZ2UKICAgICAgL1BhcmVudCAyIDAgUgogICAgICAvUmVzb3VyY2VzCiAgICAgICA8PCAvRm9udAogICAgICAgICAgIDw8IC9GMQogICAgICAgICAgICAgICA8PCAvVHlwZSAvRm9udAogICAgICAgICAgICAgICAgICAvU3VidHlwZSAvVHlwZTEKICAgICAgICAgICAgICAgICAgL0Jhc2VGb250IC9UaW1lcy1Sb21hbgogICAgICAgICAgICAgICA+PgogICAgICAgICAgID4+CiAgICAgICA+PgogICAgICAvQ29udGVudHMgNCAwIFIKICA+PgplbmRvYmoKCjQgMCBvYmoKICA8PCAvTGVuZ3RoIDU1ID4+CnN0cmVhbQogIEJUCiAgICAvRjEgMTggVGYKICAgIDAgMCBUZAogICAgKEhlbGxvIFdvcmxkKSBUagogIEVUCmVuZHN0cmVhbQplbmRvYmoKCnhyZWYKMCA1CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDAxOCAwMDAwMCBuIAowMDAwMDAwMDc3IDAwMDAwIG4gCjAwMDAwMDAxNzggMDAwMDAgbiAKMDAwMDAwMDQ1NyAwMDAwMCBuIAp0cmFpbGVyCiAgPDwgIC9Sb290IDEgMCBSCiAgICAgIC9TaXplIDUKICA+PgpzdGFydHhyZWYKNTY1CiUlRU9GCg==
------=_Part_4200734_24778174.1344608186754--
"""
PDF_PARSED = b'''%PDF-1.1\n%\xc2\xa5\xc2\xb1\xc3\xab\n\n1 0 obj\n << /Type /Catalog\n /Pages 2 0 R\n >>\nendobj\n\n2 0 obj\n << /Type /Pages\n /Kids [3 0 R]\n /Count 1\n /MediaBox [0 0 300 144]\n >>\nendobj\n\n3 0 obj\n << /Type /Page\n /Parent 2 0 R\n /Resources\n << /Font\n << /F1\n << /Type /Font\n /Subtype /Type1\n /BaseFont /Times-Roman\n >>\n >>\n >>\n /Contents 4 0 R\n >>\nendobj\n\n4 0 obj\n << /Length 55 >>\nstream\n BT\n /F1 18 Tf\n 0 0 Td\n (Hello World) Tj\n ET\nendstream\nendobj\n\nxref\n0 5\n0000000000 65535 f \n0000000018 00000 n \n0000000077 00000 n \n0000000178 00000 n \n0000000457 00000 n \ntrailer\n << /Root 1 0 R\n /Size 5\n >>\nstartxref\n565\n%%EOF\n'''
@@ -83,6 +83,19 @@ class TestEmailParsing(MailCommon):
res = self.env['mail.thread'].message_parse(self.from_string(test_mail_data.MAIL_MULTIPART_WEIRD_FILENAME))
self.assertEqual(res['attachments'][0][0], '62_@;,][)=.(ÇÀÉ.txt')
def test_message_parse_attachment_pdf_nonstandard_mime(self):
# This test checks if aliasing content-type (mime type) of "pdf" with "application/pdf" works correctly. (i.e. Treat "pdf" as "application/pdf")
# Baseline check. Parsing mail with "application/pdf"
mail_with_standard_mime = self.format(test_mail_data.MAIL_PDF_MIME_TEMPLATE, pdf_mime="application/pdf")
res_std = self.env['mail.thread'].message_parse(self.from_string(mail_with_standard_mime))
self.assertEqual(res_std['attachments'][0].content, test_mail_data.PDF_PARSED, "Attachment with Content-Type: application/pdf must parse without error")
# Parsing the same email, but with content-type set to "pdf"
mail_with_aliased_mime = self.format(test_mail_data.MAIL_PDF_MIME_TEMPLATE, pdf_mime="pdf")
res_alias = self.env['mail.thread'].message_parse(self.from_string(mail_with_aliased_mime))
self.assertEqual(res_alias['attachments'][0].content, test_mail_data.PDF_PARSED, "Attachment with aliased Content-Type: pdf must parse without error")
def test_message_parse_bugs(self):
""" Various corner cases or message parsing """
# message without Final-Recipient