mirror of
https://github.com/pacnpal/django-anymail.git
synced 2025-12-20 03:41:05 -05:00
@@ -43,6 +43,8 @@ Fixes
|
|||||||
* **Mailjet:** Avoid a Mailjet API error when sending an inline image without a
|
* **Mailjet:** Avoid a Mailjet API error when sending an inline image without a
|
||||||
filename. (Anymail now substitutes ``"attachment"`` for the missing filename.)
|
filename. (Anymail now substitutes ``"attachment"`` for the missing filename.)
|
||||||
(Thanks to `@chickahoona`_ for reporting the issue.)
|
(Thanks to `@chickahoona`_ for reporting the issue.)
|
||||||
|
* **Mailjet:** Fix a JSON parsing error on Mailjet 429 "too many requests" API
|
||||||
|
responses. (Thanks to `@rodrigondec`_ for reporting the issue.)
|
||||||
|
|
||||||
|
|
||||||
v12.0
|
v12.0
|
||||||
@@ -1779,6 +1781,7 @@ Features
|
|||||||
.. _@originell: https://github.com/originell
|
.. _@originell: https://github.com/originell
|
||||||
.. _@puru02: https://github.com/puru02
|
.. _@puru02: https://github.com/puru02
|
||||||
.. _@RignonNoel: https://github.com/RignonNoel
|
.. _@RignonNoel: https://github.com/RignonNoel
|
||||||
|
.. _@rodrigondec: https://github.com/rodrigondec
|
||||||
.. _@sblondon: https://github.com/sblondon
|
.. _@sblondon: https://github.com/sblondon
|
||||||
.. _@scur-iolus: https://github.com/scur-iolus
|
.. _@scur-iolus: https://github.com/scur-iolus
|
||||||
.. _@sdarwin: https://github.com/sdarwin
|
.. _@sdarwin: https://github.com/sdarwin
|
||||||
|
|||||||
@@ -34,7 +34,10 @@ class EmailBackend(AnymailRequestsBackend):
|
|||||||
return MailjetPayload(message, defaults, self)
|
return MailjetPayload(message, defaults, self)
|
||||||
|
|
||||||
def raise_for_status(self, response, payload, message):
|
def raise_for_status(self, response, payload, message):
|
||||||
if 400 <= response.status_code <= 499:
|
content_type = (
|
||||||
|
response.headers.get("content-type", "").split(";")[0].strip().lower()
|
||||||
|
)
|
||||||
|
if 400 <= response.status_code <= 499 and content_type == "application/json":
|
||||||
# Mailjet uses 4xx status codes for partial failure in batch send;
|
# Mailjet uses 4xx status codes for partial failure in batch send;
|
||||||
# we'll determine how to handle below in parse_recipient_status.
|
# we'll determine how to handle below in parse_recipient_status.
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from django.test import SimpleTestCase, override_settings, tag
|
|||||||
|
|
||||||
from anymail.exceptions import (
|
from anymail.exceptions import (
|
||||||
AnymailAPIError,
|
AnymailAPIError,
|
||||||
|
AnymailRequestsAPIError,
|
||||||
AnymailSerializationError,
|
AnymailSerializationError,
|
||||||
AnymailUnsupportedFeature,
|
AnymailUnsupportedFeature,
|
||||||
)
|
)
|
||||||
@@ -690,8 +691,7 @@ class MailjetBackendAnymailFeatureTests(MailjetBackendMockAPITestCase):
|
|||||||
# Mailjet's v3.1 API will partially fail a batch send, allowing valid emails
|
# Mailjet's v3.1 API will partially fail a batch send, allowing valid emails
|
||||||
# to go out. The API response doesn't identify the failed email addresses;
|
# to go out. The API response doesn't identify the failed email addresses;
|
||||||
# make sure we represent them correctly in the anymail_status.
|
# make sure we represent them correctly in the anymail_status.
|
||||||
response_content = json.dumps(
|
response_data = {
|
||||||
{
|
|
||||||
"Messages": [
|
"Messages": [
|
||||||
{
|
{
|
||||||
"Status": "success",
|
"Status": "success",
|
||||||
@@ -724,9 +724,8 @@ class MailjetBackendAnymailFeatureTests(MailjetBackendMockAPITestCase):
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
).encode("utf-8")
|
|
||||||
# Mailjet uses 400 for partial success:
|
# Mailjet uses 400 for partial success:
|
||||||
self.set_mock_response(raw=response_content, status_code=400)
|
self.set_mock_response(json_data=response_data, status_code=400)
|
||||||
msg = mail.EmailMessage(
|
msg = mail.EmailMessage(
|
||||||
"Subject",
|
"Subject",
|
||||||
"Message",
|
"Message",
|
||||||
@@ -751,7 +750,7 @@ class MailjetBackendAnymailFeatureTests(MailjetBackendMockAPITestCase):
|
|||||||
msg.anymail_status.recipients["invalid@123.4"].message_id, None
|
msg.anymail_status.recipients["invalid@123.4"].message_id, None
|
||||||
)
|
)
|
||||||
self.assertEqual(msg.anymail_status.message_id, {"12345678901234500", None})
|
self.assertEqual(msg.anymail_status.message_id, {"12345678901234500", None})
|
||||||
self.assertEqual(msg.anymail_status.esp_response.content, response_content)
|
self.assertEqual(msg.anymail_status.esp_response.json(), response_data)
|
||||||
|
|
||||||
# noinspection PyUnresolvedReferences
|
# noinspection PyUnresolvedReferences
|
||||||
def test_send_failed_anymail_status(self):
|
def test_send_failed_anymail_status(self):
|
||||||
@@ -764,6 +763,18 @@ class MailjetBackendAnymailFeatureTests(MailjetBackendMockAPITestCase):
|
|||||||
self.assertEqual(self.message.anymail_status.recipients, {})
|
self.assertEqual(self.message.anymail_status.recipients, {})
|
||||||
self.assertIsNone(self.message.anymail_status.esp_response)
|
self.assertIsNone(self.message.anymail_status.esp_response)
|
||||||
|
|
||||||
|
def test_non_json_error(self):
|
||||||
|
"""429 (and other?) errors don't have a json payload"""
|
||||||
|
self.set_mock_response(
|
||||||
|
status_code=429, raw=b"Rate limit exceeded", content_type="text/html"
|
||||||
|
)
|
||||||
|
with self.assertRaisesRegex(
|
||||||
|
AnymailRequestsAPIError,
|
||||||
|
r"^Mailjet API response 429 .*Rate limit exceeded.*",
|
||||||
|
) as cm:
|
||||||
|
self.message.send()
|
||||||
|
self.assertNotIn("Invalid JSON", str(cm.exception))
|
||||||
|
|
||||||
# noinspection PyUnresolvedReferences
|
# noinspection PyUnresolvedReferences
|
||||||
def test_send_unparsable_response(self):
|
def test_send_unparsable_response(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user