mirror of
https://github.com/pacnpal/django-anymail.git
synced 2025-12-20 03:41:05 -05:00
@@ -53,6 +53,8 @@ Features
|
|||||||
* **Brevo (Sendinblue):** Add support for inbound email. (See
|
* **Brevo (Sendinblue):** Add support for inbound email. (See
|
||||||
`docs <https://anymail.dev/en/latest/esps/sendinblue/#sendinblue-inbound>`_.)
|
`docs <https://anymail.dev/en/latest/esps/sendinblue/#sendinblue-inbound>`_.)
|
||||||
|
|
||||||
|
* **SendGrid:** Support for multiple ``reply_to`` addresses.
|
||||||
|
(Thanks to `@gdvalderrama`_ for pointing out the new API.)
|
||||||
|
|
||||||
Deprecations
|
Deprecations
|
||||||
~~~~~~~~~~~~
|
~~~~~~~~~~~~
|
||||||
@@ -1546,6 +1548,7 @@ Features
|
|||||||
.. _@ewingrj: https://github.com/ewingrj
|
.. _@ewingrj: https://github.com/ewingrj
|
||||||
.. _@fdemmer: https://github.com/fdemmer
|
.. _@fdemmer: https://github.com/fdemmer
|
||||||
.. _@Flexonze: https://github.com/Flexonze
|
.. _@Flexonze: https://github.com/Flexonze
|
||||||
|
.. _@gdvalderrama: https://github.com/gdvalderrama
|
||||||
.. _@Honza-m: https://github.com/Honza-m
|
.. _@Honza-m: https://github.com/Honza-m
|
||||||
.. _@janneThoft: https://github.com/janneThoft
|
.. _@janneThoft: https://github.com/janneThoft
|
||||||
.. _@jc-ee: https://github.com/jc-ee
|
.. _@jc-ee: https://github.com/jc-ee
|
||||||
|
|||||||
@@ -254,11 +254,8 @@ class SendGridPayload(RequestsPayload):
|
|||||||
self.data["subject"] = subject
|
self.data["subject"] = subject
|
||||||
|
|
||||||
def set_reply_to(self, emails):
|
def set_reply_to(self, emails):
|
||||||
# SendGrid only supports a single address in the reply_to API param.
|
if emails:
|
||||||
if len(emails) > 1:
|
self.data["reply_to_list"] = [self.email_object(email) for email in emails]
|
||||||
self.unsupported_feature("multiple reply_to addresses")
|
|
||||||
if len(emails) > 0:
|
|
||||||
self.data["reply_to"] = self.email_object(emails[0])
|
|
||||||
|
|
||||||
def set_extra_headers(self, headers):
|
def set_extra_headers(self, headers):
|
||||||
# SendGrid requires header values to be strings -- not integers.
|
# SendGrid requires header values to be strings -- not integers.
|
||||||
|
|||||||
@@ -202,14 +202,6 @@ Limitations and quirks
|
|||||||
webhook :attr:`message_id` will fall back to "smtp-id" when "anymail_id"
|
webhook :attr:`message_id` will fall back to "smtp-id" when "anymail_id"
|
||||||
isn't present.)
|
isn't present.)
|
||||||
|
|
||||||
**Single Reply-To**
|
|
||||||
SendGrid's v3 API only supports a single Reply-To address.
|
|
||||||
|
|
||||||
If your message has multiple reply addresses, you'll get an
|
|
||||||
:exc:`~anymail.exceptions.AnymailUnsupportedFeature` error---or
|
|
||||||
if you've enabled :setting:`ANYMAIL_IGNORE_UNSUPPORTED_FEATURES`,
|
|
||||||
Anymail will use only the first one.
|
|
||||||
|
|
||||||
**Invalid Addresses**
|
**Invalid Addresses**
|
||||||
SendGrid will accept *and send* just about anything as
|
SendGrid will accept *and send* just about anything as
|
||||||
a message's :attr:`from_email`. (And email protocols are
|
a message's :attr:`from_email`. (And email protocols are
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ class SendGridBackendStandardEmailTests(SendGridBackendMockAPITestCase):
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
data["content"], [{"type": "text/plain", "value": "Body goes here"}]
|
data["content"], [{"type": "text/plain", "value": "Body goes here"}]
|
||||||
)
|
)
|
||||||
self.assertEqual(data["reply_to"], {"email": "another@example.com"})
|
self.assertEqual(data["reply_to_list"], [{"email": "another@example.com"}])
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
data["headers"],
|
data["headers"],
|
||||||
{
|
{
|
||||||
@@ -243,7 +243,8 @@ class SendGridBackendStandardEmailTests(SendGridBackendMockAPITestCase):
|
|||||||
# Reply-To must be moved to separate param
|
# Reply-To must be moved to separate param
|
||||||
self.assertNotIn("Reply-To", data["headers"])
|
self.assertNotIn("Reply-To", data["headers"])
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
data["reply_to"], {"name": "Do Not Reply", "email": "noreply@example.com"}
|
data["reply_to_list"],
|
||||||
|
[{"name": "Do Not Reply", "email": "noreply@example.com"}],
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_extra_headers_serialization_error(self):
|
def test_extra_headers_serialization_error(self):
|
||||||
@@ -252,26 +253,6 @@ class SendGridBackendStandardEmailTests(SendGridBackendMockAPITestCase):
|
|||||||
self.message.send()
|
self.message.send()
|
||||||
|
|
||||||
def test_reply_to(self):
|
def test_reply_to(self):
|
||||||
self.message.reply_to = ['"Reply recipient" <reply@example.com']
|
|
||||||
self.message.send()
|
|
||||||
data = self.get_api_call_json()
|
|
||||||
self.assertEqual(
|
|
||||||
data["reply_to"], {"name": "Reply recipient", "email": "reply@example.com"}
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_multiple_reply_to(self):
|
|
||||||
# SendGrid v3 prohibits Reply-To in custom headers,
|
|
||||||
# and only allows a single reply address
|
|
||||||
self.message.reply_to = [
|
|
||||||
'"Reply recipient" <reply@example.com',
|
|
||||||
"reply2@example.com",
|
|
||||||
]
|
|
||||||
with self.assertRaises(AnymailUnsupportedFeature):
|
|
||||||
self.message.send()
|
|
||||||
|
|
||||||
@override_settings(ANYMAIL_IGNORE_UNSUPPORTED_FEATURES=True)
|
|
||||||
def test_multiple_reply_to_ignore_unsupported(self):
|
|
||||||
# Should use first Reply-To if ignoring unsupported features
|
|
||||||
self.message.reply_to = [
|
self.message.reply_to = [
|
||||||
'"Reply recipient" <reply@example.com',
|
'"Reply recipient" <reply@example.com',
|
||||||
"reply2@example.com",
|
"reply2@example.com",
|
||||||
@@ -279,8 +260,13 @@ class SendGridBackendStandardEmailTests(SendGridBackendMockAPITestCase):
|
|||||||
self.message.send()
|
self.message.send()
|
||||||
data = self.get_api_call_json()
|
data = self.get_api_call_json()
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
data["reply_to"], {"name": "Reply recipient", "email": "reply@example.com"}
|
data["reply_to_list"],
|
||||||
|
[
|
||||||
|
{"name": "Reply recipient", "email": "reply@example.com"},
|
||||||
|
{"email": "reply2@example.com"},
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
self.assertNotIn("reply_to", data) # not allowed with reply_to_list
|
||||||
|
|
||||||
def test_attachments(self):
|
def test_attachments(self):
|
||||||
text_content = "* Item one\n* Item two\n* Item three"
|
text_content = "* Item one\n* Item two\n* Item three"
|
||||||
@@ -1050,6 +1036,8 @@ class SendGridBackendAnymailFeatureTests(SendGridBackendMockAPITestCase):
|
|||||||
self.assertNotIn("headers", data)
|
self.assertNotIn("headers", data)
|
||||||
self.assertNotIn("ip_pool_name", data)
|
self.assertNotIn("ip_pool_name", data)
|
||||||
self.assertNotIn("mail_settings", data)
|
self.assertNotIn("mail_settings", data)
|
||||||
|
self.assertNotIn("reply_to", data)
|
||||||
|
self.assertNotIn("reply_to_list", data)
|
||||||
self.assertNotIn("sections", data)
|
self.assertNotIn("sections", data)
|
||||||
self.assertNotIn("send_at", data)
|
self.assertNotIn("send_at", data)
|
||||||
self.assertNotIn("template_id", data)
|
self.assertNotIn("template_id", data)
|
||||||
|
|||||||
@@ -82,8 +82,7 @@ class SendGridBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
|
|||||||
to=["to1@sink.sendgrid.net", '"Recipient 2, OK?" <to2@sink.sendgrid.net>'],
|
to=["to1@sink.sendgrid.net", '"Recipient 2, OK?" <to2@sink.sendgrid.net>'],
|
||||||
cc=["cc1@sink.sendgrid.net", "Copy 2 <cc2@sink.sendgrid.net>"],
|
cc=["cc1@sink.sendgrid.net", "Copy 2 <cc2@sink.sendgrid.net>"],
|
||||||
bcc=["bcc1@sink.sendgrid.net", "Blind Copy 2 <bcc2@sink.sendgrid.net>"],
|
bcc=["bcc1@sink.sendgrid.net", "Blind Copy 2 <bcc2@sink.sendgrid.net>"],
|
||||||
# v3 only supports single reply-to:
|
reply_to=['"Reply, with comma" <reply@example.com>', "reply2@example.com"],
|
||||||
reply_to=['"Reply, with comma" <reply@example.com>'],
|
|
||||||
headers={"X-Anymail-Test": "value", "X-Anymail-Count": 3},
|
headers={"X-Anymail-Test": "value", "X-Anymail-Count": 3},
|
||||||
metadata={"meta1": "simple string", "meta2": 2},
|
metadata={"meta1": "simple string", "meta2": 2},
|
||||||
send_at=send_at,
|
send_at=send_at,
|
||||||
|
|||||||
Reference in New Issue
Block a user