mirror of
https://github.com/pacnpal/django-anymail.git
synced 2025-12-20 03:41:05 -05:00
MailerSend: support extra headers
MailerSend added a `"headers"` API field (which is available to "Enterprise accounts only").
This commit is contained in:
@@ -55,6 +55,9 @@ Features
|
|||||||
and ``tags`` when sending with a ``template_id``.
|
and ``tags`` when sending with a ``template_id``.
|
||||||
(Requires boto3 v1.34.98 or later.)
|
(Requires boto3 v1.34.98 or later.)
|
||||||
|
|
||||||
|
* **MailerSend:** Allow all extra headers. (Note that MailerSend limits use
|
||||||
|
of this feature to "Enterprise accounts only.")
|
||||||
|
|
||||||
Fixes
|
Fixes
|
||||||
~~~~~
|
~~~~~
|
||||||
|
|
||||||
|
|||||||
@@ -242,8 +242,8 @@ class MailerSendPayload(RequestsPayload):
|
|||||||
self.data["reply_to"] = self.make_mailersend_email(emails[0])
|
self.data["reply_to"] = self.make_mailersend_email(emails[0])
|
||||||
|
|
||||||
def set_extra_headers(self, headers):
|
def set_extra_headers(self, headers):
|
||||||
# MailerSend doesn't support arbitrary email headers, but has
|
# MailerSend has individual API params for In-Reply-To and Precedence: bulk.
|
||||||
# individual API params for In-Reply-To and Precedence: bulk.
|
# The general "headers" option "is available to Enterprise accounts only".
|
||||||
# (headers is a CaseInsensitiveDict, and is a copy so safe to modify.)
|
# (headers is a CaseInsensitiveDict, and is a copy so safe to modify.)
|
||||||
in_reply_to = headers.pop("In-Reply-To", None)
|
in_reply_to = headers.pop("In-Reply-To", None)
|
||||||
if in_reply_to is not None:
|
if in_reply_to is not None:
|
||||||
@@ -256,7 +256,9 @@ class MailerSendPayload(RequestsPayload):
|
|||||||
self.data["precedence_bulk"] = is_bulk
|
self.data["precedence_bulk"] = is_bulk
|
||||||
|
|
||||||
if headers:
|
if headers:
|
||||||
self.unsupported_feature("most extra_headers (see docs)")
|
self.data["headers"] = [
|
||||||
|
{"name": field, "value": value} for field, value in headers.items()
|
||||||
|
]
|
||||||
|
|
||||||
def set_text_body(self, body):
|
def set_text_body(self, body):
|
||||||
self.data["text"] = body
|
self.data["text"] = body
|
||||||
|
|||||||
@@ -204,7 +204,12 @@ see :ref:`unsupported-features`.
|
|||||||
Anymail will use only the first one.
|
Anymail will use only the first one.
|
||||||
|
|
||||||
**Limited extra headers**
|
**Limited extra headers**
|
||||||
MailerSend does not allow most extra headers. There are two exceptions:
|
MailerSend allows extra email headers for "Enterprise accounts only."
|
||||||
|
If you try to send :ref:`extra headers <message-headers>` with a non-enterprise
|
||||||
|
account, you may receive an API error.
|
||||||
|
|
||||||
|
However, MailerSend has special handling for two headers,
|
||||||
|
and *any* MailerSend account can send messages with them:
|
||||||
|
|
||||||
* You can include :mailheader:`In-Reply-To` in extra headers, set to
|
* You can include :mailheader:`In-Reply-To` in extra headers, set to
|
||||||
a message-id (without the angle brackets).
|
a message-id (without the angle brackets).
|
||||||
@@ -216,7 +221,10 @@ see :ref:`unsupported-features`.
|
|||||||
if your extra headers have :mailheader:`Precedence` set to ``"bulk"`` or
|
if your extra headers have :mailheader:`Precedence` set to ``"bulk"`` or
|
||||||
``"list"`` or ``"junk"``, or ``false`` for any other value.
|
``"list"`` or ``"junk"``, or ``false`` for any other value.
|
||||||
|
|
||||||
Any other extra headers will raise an
|
.. versionchanged:: 11.0
|
||||||
|
|
||||||
|
In earlier releases, attempting to send other headers
|
||||||
|
(even with an enterprise account) would raise an
|
||||||
:exc:`~anymail.exceptions.AnymailUnsupportedFeature` error.
|
:exc:`~anymail.exceptions.AnymailUnsupportedFeature` error.
|
||||||
|
|
||||||
**No merge headers support**
|
**No merge headers support**
|
||||||
|
|||||||
@@ -145,23 +145,6 @@ class MailerSendBackendStandardEmailTests(MailerSendBackendMockAPITestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_custom_headers(self):
|
def test_custom_headers(self):
|
||||||
email = mail.EmailMessage(
|
|
||||||
"Subject",
|
|
||||||
"Body goes here",
|
|
||||||
"from@example.com",
|
|
||||||
["to1@example.com"],
|
|
||||||
headers={
|
|
||||||
"Reply-To": "another@example.com",
|
|
||||||
"In-Reply-To": "12345@example.com",
|
|
||||||
"X-MyHeader": "my value",
|
|
||||||
"Message-ID": "mycustommsgid@example.com",
|
|
||||||
"Precedence": "Bulk",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
with self.assertRaisesMessage(AnymailUnsupportedFeature, "extra_headers"):
|
|
||||||
email.send()
|
|
||||||
|
|
||||||
def test_supported_custom_headers(self):
|
|
||||||
email = mail.EmailMessage(
|
email = mail.EmailMessage(
|
||||||
"Subject",
|
"Subject",
|
||||||
"Body goes here",
|
"Body goes here",
|
||||||
@@ -171,13 +154,20 @@ class MailerSendBackendStandardEmailTests(MailerSendBackendMockAPITestCase):
|
|||||||
"Reply-To": "another@example.com",
|
"Reply-To": "another@example.com",
|
||||||
"In-Reply-To": "12345@example.com",
|
"In-Reply-To": "12345@example.com",
|
||||||
"Precedence": "Bulk",
|
"Precedence": "Bulk",
|
||||||
|
# Other custom headers only available to enterprise accounts:
|
||||||
|
"X-Custom": "custom header",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
email.send()
|
email.send()
|
||||||
data = self.get_api_call_json()
|
data = self.get_api_call_json()
|
||||||
|
# Special handling headers:
|
||||||
self.assertEqual(data["reply_to"], {"email": "another@example.com"})
|
self.assertEqual(data["reply_to"], {"email": "another@example.com"})
|
||||||
self.assertEqual(data["in_reply_to"], "12345@example.com")
|
self.assertEqual(data["in_reply_to"], "12345@example.com")
|
||||||
self.assertIs(data["precedence_bulk"], True)
|
self.assertIs(data["precedence_bulk"], True)
|
||||||
|
# Other headers:
|
||||||
|
self.assertEqual(
|
||||||
|
data["headers"], [{"name": "X-Custom", "value": "custom header"}]
|
||||||
|
)
|
||||||
|
|
||||||
def test_html_message(self):
|
def test_html_message(self):
|
||||||
text_content = "This is an important message."
|
text_content = "This is an important message."
|
||||||
@@ -607,6 +597,7 @@ class MailerSendBackendAnymailFeatureTests(MailerSendBackendMockAPITestCase):
|
|||||||
self.assertNotIn("reply_to", data)
|
self.assertNotIn("reply_to", data)
|
||||||
self.assertNotIn("html", data)
|
self.assertNotIn("html", data)
|
||||||
self.assertNotIn("attachments", data)
|
self.assertNotIn("attachments", data)
|
||||||
|
self.assertNotIn("headers", data)
|
||||||
self.assertNotIn("template_id", data)
|
self.assertNotIn("template_id", data)
|
||||||
self.assertNotIn("tags", data)
|
self.assertNotIn("tags", data)
|
||||||
self.assertNotIn("variables", data)
|
self.assertNotIn("variables", data)
|
||||||
|
|||||||
@@ -81,8 +81,13 @@ class MailerSendBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
|
|||||||
bcc=["test+bcc1@anymail.dev", "Blind Copy 2 <test+bcc2@anymail.dev>"],
|
bcc=["test+bcc1@anymail.dev", "Blind Copy 2 <test+bcc2@anymail.dev>"],
|
||||||
# MailerSend only supports single reply_to:
|
# MailerSend only supports single reply_to:
|
||||||
reply_to=["Reply <reply@example.com>"],
|
reply_to=["Reply <reply@example.com>"],
|
||||||
# MailerSend supports very limited extra headers:
|
headers={
|
||||||
headers={"Precedence": "bulk", "In-Reply-To": "earlier-id@anymail.dev"},
|
# Special handling for these headers (available to all accounts):
|
||||||
|
"Precedence": "bulk",
|
||||||
|
"In-Reply-To": "earlier-id@anymail.dev",
|
||||||
|
# Only "enterprise accounts" can send other custom headers:
|
||||||
|
"X-Custom": "anymail test",
|
||||||
|
},
|
||||||
send_at=send_at,
|
send_at=send_at,
|
||||||
tags=["tag 1", "tag 2"],
|
tags=["tag 1", "tag 2"],
|
||||||
track_clicks=False,
|
track_clicks=False,
|
||||||
|
|||||||
Reference in New Issue
Block a user