mirror of
https://github.com/pacnpal/django-anymail.git
synced 2025-12-19 19:31:06 -05:00
Mailjet: Prevent empty attachment filename
Mailjet requires all attachments/inlines have a non-empty Filename field. Substitute `"attachment"` for missing filenames. Fixes #407.
This commit is contained in:
@@ -37,6 +37,13 @@ Breaking changes
|
|||||||
(Postal's signature verification uses the "cryptography" package, which is no
|
(Postal's signature verification uses the "cryptography" package, which is no
|
||||||
longer reliably installable with Python 3.8.)
|
longer reliably installable with Python 3.8.)
|
||||||
|
|
||||||
|
Fixes
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
* **Mailjet:** Avoid a Mailjet API error when sending an inline image without a
|
||||||
|
filename. (Anymail now substitutes ``"attachment"`` for the missing filename.)
|
||||||
|
(Thanks to `@chickahoona`_ for reporting the issue.)
|
||||||
|
|
||||||
|
|
||||||
v12.0
|
v12.0
|
||||||
-----
|
-----
|
||||||
@@ -1737,6 +1744,7 @@ Features
|
|||||||
.. _@b0d0nne11: https://github.com/b0d0nne11
|
.. _@b0d0nne11: https://github.com/b0d0nne11
|
||||||
.. _@calvin: https://github.com/calvin
|
.. _@calvin: https://github.com/calvin
|
||||||
.. _@carrerasrodrigo: https://github.com/carrerasrodrigo
|
.. _@carrerasrodrigo: https://github.com/carrerasrodrigo
|
||||||
|
.. _@chickahoona: https://github.com/chickahoona
|
||||||
.. _@chrisgrande: https://github.com/chrisgrande
|
.. _@chrisgrande: https://github.com/chrisgrande
|
||||||
.. _@cjsoftuk: https://github.com/cjsoftuk
|
.. _@cjsoftuk: https://github.com/cjsoftuk
|
||||||
.. _@costela: https://github.com/costela
|
.. _@costela: https://github.com/costela
|
||||||
|
|||||||
@@ -195,7 +195,8 @@ class MailjetPayload(RequestsPayload):
|
|||||||
def add_attachment(self, attachment):
|
def add_attachment(self, attachment):
|
||||||
att = {
|
att = {
|
||||||
"ContentType": attachment.mimetype,
|
"ContentType": attachment.mimetype,
|
||||||
"Filename": attachment.name or "",
|
# Mailjet requires a non-empty Filename.
|
||||||
|
"Filename": attachment.name or "attachment",
|
||||||
"Base64Content": attachment.b64content,
|
"Base64Content": attachment.b64content,
|
||||||
}
|
}
|
||||||
if attachment.inline:
|
if attachment.inline:
|
||||||
|
|||||||
@@ -144,6 +144,15 @@ Limitations and quirks
|
|||||||
:ref:`esp-send-status`, because Mailjet's other (statistics, event tracking)
|
:ref:`esp-send-status`, because Mailjet's other (statistics, event tracking)
|
||||||
APIs don't yet support MessageUUID.
|
APIs don't yet support MessageUUID.
|
||||||
|
|
||||||
|
**Attachments require filenames**
|
||||||
|
Mailjet requires that all attachments and inline images have filenames. If you
|
||||||
|
don't supply a filename, Anymail will use ``"attachment"`` as the filename.
|
||||||
|
|
||||||
|
.. versionchanged:: 13.0
|
||||||
|
|
||||||
|
Earlier Anymail versions would default to an empty string, resulting in
|
||||||
|
a Mailjet API error.
|
||||||
|
|
||||||
**Older limitations**
|
**Older limitations**
|
||||||
|
|
||||||
.. versionchanged:: 6.0
|
.. versionchanged:: 6.0
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from anymail.exceptions import (
|
|||||||
AnymailSerializationError,
|
AnymailSerializationError,
|
||||||
AnymailUnsupportedFeature,
|
AnymailUnsupportedFeature,
|
||||||
)
|
)
|
||||||
from anymail.message import attach_inline_image_file
|
from anymail.message import attach_inline_image, attach_inline_image_file
|
||||||
|
|
||||||
from .mock_requests_backend import (
|
from .mock_requests_backend import (
|
||||||
RequestsBackendMockAPITestCase,
|
RequestsBackendMockAPITestCase,
|
||||||
@@ -266,7 +266,7 @@ class MailjetBackendStandardEmailTests(MailjetBackendMockAPITestCase):
|
|||||||
self.assertNotIn("ContentID", attachments[1])
|
self.assertNotIn("ContentID", attachments[1])
|
||||||
|
|
||||||
self.assertEqual(attachments[2]["ContentType"], "application/pdf")
|
self.assertEqual(attachments[2]["ContentType"], "application/pdf")
|
||||||
self.assertEqual(attachments[2]["Filename"], "") # none
|
self.assertEqual(attachments[2]["Filename"], "attachment")
|
||||||
self.assertEqual(decode_att(attachments[2]["Base64Content"]), pdf_content)
|
self.assertEqual(decode_att(attachments[2]["Base64Content"]), pdf_content)
|
||||||
self.assertNotIn("ContentID", attachments[2])
|
self.assertNotIn("ContentID", attachments[2])
|
||||||
|
|
||||||
@@ -297,6 +297,7 @@ class MailjetBackendStandardEmailTests(MailjetBackendMockAPITestCase):
|
|||||||
image_data = sample_image_content(image_filename)
|
image_data = sample_image_content(image_filename)
|
||||||
|
|
||||||
cid = attach_inline_image_file(self.message, image_path) # Read from a png file
|
cid = attach_inline_image_file(self.message, image_path) # Read from a png file
|
||||||
|
cid2 = attach_inline_image(self.message, image_data)
|
||||||
html_content = (
|
html_content = (
|
||||||
'<p>This has an <img src="cid:%s" alt="inline" /> image.</p>' % cid
|
'<p>This has an <img src="cid:%s" alt="inline" /> image.</p>' % cid
|
||||||
)
|
)
|
||||||
@@ -307,11 +308,16 @@ class MailjetBackendStandardEmailTests(MailjetBackendMockAPITestCase):
|
|||||||
self.assertEqual(data["Globals"]["HTMLPart"], html_content)
|
self.assertEqual(data["Globals"]["HTMLPart"], html_content)
|
||||||
|
|
||||||
attachments = data["Globals"]["InlinedAttachments"]
|
attachments = data["Globals"]["InlinedAttachments"]
|
||||||
self.assertEqual(len(attachments), 1)
|
self.assertEqual(len(attachments), 2)
|
||||||
self.assertEqual(attachments[0]["Filename"], image_filename)
|
self.assertEqual(attachments[0]["Filename"], image_filename)
|
||||||
self.assertEqual(attachments[0]["ContentID"], cid)
|
self.assertEqual(attachments[0]["ContentID"], cid)
|
||||||
self.assertEqual(attachments[0]["ContentType"], "image/png")
|
self.assertEqual(attachments[0]["ContentType"], "image/png")
|
||||||
self.assertEqual(decode_att(attachments[0]["Base64Content"]), image_data)
|
self.assertEqual(decode_att(attachments[0]["Base64Content"]), image_data)
|
||||||
|
# Mailjet requires a filename for all attachments, so make sure it's not empty:
|
||||||
|
self.assertEqual(attachments[1]["Filename"], "attachment")
|
||||||
|
self.assertEqual(attachments[1]["ContentID"], cid2)
|
||||||
|
self.assertEqual(attachments[1]["ContentType"], "image/png")
|
||||||
|
self.assertEqual(decode_att(attachments[1]["Base64Content"]), image_data)
|
||||||
|
|
||||||
self.assertNotIn("Attachments", data["Globals"])
|
self.assertNotIn("Attachments", data["Globals"])
|
||||||
|
|
||||||
@@ -340,7 +346,7 @@ class MailjetBackendStandardEmailTests(MailjetBackendMockAPITestCase):
|
|||||||
"Base64Content": image_data_b64,
|
"Base64Content": image_data_b64,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Filename": "", # the unnamed one
|
"Filename": "attachment", # the unnamed one
|
||||||
"ContentType": "image/png",
|
"ContentType": "image/png",
|
||||||
"Base64Content": image_data_b64,
|
"Base64Content": image_data_b64,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from django.test import SimpleTestCase, override_settings, tag
|
|||||||
from anymail.exceptions import AnymailAPIError
|
from anymail.exceptions import AnymailAPIError
|
||||||
from anymail.message import AnymailMessage
|
from anymail.message import AnymailMessage
|
||||||
|
|
||||||
from .utils import AnymailTestMixin, sample_image_path
|
from .utils import AnymailTestMixin, sample_image_content
|
||||||
|
|
||||||
ANYMAIL_TEST_MAILJET_API_KEY = os.getenv("ANYMAIL_TEST_MAILJET_API_KEY")
|
ANYMAIL_TEST_MAILJET_API_KEY = os.getenv("ANYMAIL_TEST_MAILJET_API_KEY")
|
||||||
ANYMAIL_TEST_MAILJET_SECRET_KEY = os.getenv("ANYMAIL_TEST_MAILJET_SECRET_KEY")
|
ANYMAIL_TEST_MAILJET_SECRET_KEY = os.getenv("ANYMAIL_TEST_MAILJET_SECRET_KEY")
|
||||||
@@ -91,7 +91,7 @@ class MailjetBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
|
|||||||
)
|
)
|
||||||
message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
|
message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
|
||||||
message.attach("attachment2.csv", "ID,Name\n1,Amy Lina", "text/csv")
|
message.attach("attachment2.csv", "ID,Name\n1,Amy Lina", "text/csv")
|
||||||
cid = message.attach_inline_image_file(sample_image_path())
|
cid = message.attach_inline_image(sample_image_content())
|
||||||
message.attach_alternative(
|
message.attach_alternative(
|
||||||
"<p><b>HTML:</b> with <a href='http://example.com'>link</a>"
|
"<p><b>HTML:</b> with <a href='http://example.com'>link</a>"
|
||||||
"and image: <img src='cid:%s'></div>" % cid,
|
"and image: <img src='cid:%s'></div>" % cid,
|
||||||
|
|||||||
Reference in New Issue
Block a user