MailerSend: support extra headers

MailerSend added a `"headers"` API field
(which is available to "Enterprise
accounts only").
This commit is contained in:
Mike Edmunds
2024-06-21 17:41:33 -07:00
parent 0776b12331
commit faf98c22d7
5 changed files with 34 additions and 25 deletions

View File

@@ -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
~~~~~ ~~~~~

View File

@@ -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

View File

@@ -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**

View File

@@ -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)

View File

@@ -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,