also consider Content-ID when marking attachment as inline (#126)

Handle MIME attachments with Content-ID as inline by default.

Treat MIME attachments that have a *Content-ID* but no explicit *Content-Disposition*
header as inline, matching the behavior of many email clients.
This commit is contained in:
Leo Antunes
2018-10-11 23:29:00 +02:00
committed by Mike Edmunds
parent 4028eda583
commit 64f7d31d14
4 changed files with 62 additions and 1 deletions

View File

@@ -1,6 +1,7 @@
# Tests for the anymail/utils.py module
# (not to be confused with utilities for testing found in in tests/utils.py)
import base64
from email.mime.image import MIMEImage
from unittest import skipIf
import six
@@ -21,6 +22,7 @@ except ImportError:
from anymail.exceptions import AnymailInvalidAddress, _LazyError
from anymail.utils import (
parse_address_list, parse_single_address, EmailAddress,
Attachment,
is_lazy, force_non_lazy, force_non_lazy_dict, force_non_lazy_list,
update_deep,
get_request_uri, get_request_basic_auth, parse_rfc2822date, querydict_getfirst)
@@ -161,6 +163,51 @@ class ParseAddressListTests(SimpleTestCase):
parse_single_address(" ")
class NormalizedAttachmentTests(SimpleTestCase):
"""Test utils.Attachment"""
# (Several basic tests could be added here)
def test_content_disposition_attachment(self):
image = MIMEImage(b";-)", "x-emoticon")
image["Content-Disposition"] = 'attachment; filename="emoticon.txt"'
att = Attachment(image, "ascii")
self.assertEqual(att.name, "emoticon.txt")
self.assertEqual(att.content, b";-)")
self.assertFalse(att.inline)
self.assertIsNone(att.content_id)
self.assertEqual(att.cid, "")
def test_content_disposition_inline(self):
image = MIMEImage(b";-)", "x-emoticon")
image["Content-Disposition"] = 'inline'
att = Attachment(image, "ascii")
self.assertIsNone(att.name)
self.assertEqual(att.content, b";-)")
self.assertTrue(att.inline) # even without the Content-ID
self.assertIsNone(att.content_id)
self.assertEqual(att.cid, "")
image["Content-ID"] = "<abc123@example.net>"
att = Attachment(image, "ascii")
self.assertEqual(att.content_id, "<abc123@example.net>")
self.assertEqual(att.cid, "abc123@example.net")
def test_content_id_implies_inline(self):
"""A MIME object with a Content-ID should be assumed to be inline"""
image = MIMEImage(b";-)", "x-emoticon")
image["Content-ID"] = "<abc123@example.net>"
att = Attachment(image, "ascii")
self.assertTrue(att.inline)
self.assertEqual(att.content_id, "<abc123@example.net>")
# ... but not if explicit Content-Disposition says otherwise
image["Content-Disposition"] = "attachment"
att = Attachment(image, "ascii")
self.assertFalse(att.inline)
self.assertIsNone(att.content_id) # ignored for non-inline Attachment
class LazyCoercionTests(SimpleTestCase):
"""Test utils.is_lazy and force_non_lazy*"""