diff --git a/CHANGELOG.rst b/CHANGELOG.rst index cd174133..5e2caa9e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -53,6 +53,8 @@ Features * **Brevo (Sendinblue):** Add support for inbound email. (See `docs `_.) +* **SendGrid:** Support for multiple ``reply_to`` addresses. + (Thanks to `@gdvalderrama`_ for pointing out the new API.) Deprecations ~~~~~~~~~~~~ @@ -1546,6 +1548,7 @@ Features .. _@ewingrj: https://github.com/ewingrj .. _@fdemmer: https://github.com/fdemmer .. _@Flexonze: https://github.com/Flexonze +.. _@gdvalderrama: https://github.com/gdvalderrama .. _@Honza-m: https://github.com/Honza-m .. _@janneThoft: https://github.com/janneThoft .. _@jc-ee: https://github.com/jc-ee diff --git a/anymail/backends/sendgrid.py b/anymail/backends/sendgrid.py index 13ae941f..0c6667a9 100644 --- a/anymail/backends/sendgrid.py +++ b/anymail/backends/sendgrid.py @@ -254,11 +254,8 @@ def set_subject(self, subject): self.data["subject"] = subject def set_reply_to(self, emails): - # SendGrid only supports a single address in the reply_to API param. - if len(emails) > 1: - self.unsupported_feature("multiple reply_to addresses") - if len(emails) > 0: - self.data["reply_to"] = self.email_object(emails[0]) + if emails: + self.data["reply_to_list"] = [self.email_object(email) for email in emails] def set_extra_headers(self, headers): # SendGrid requires header values to be strings -- not integers. diff --git a/docs/esps/sendgrid.rst b/docs/esps/sendgrid.rst index ac3d1135..c1055789 100644 --- a/docs/esps/sendgrid.rst +++ b/docs/esps/sendgrid.rst @@ -202,14 +202,6 @@ Limitations and quirks webhook :attr:`message_id` will fall back to "smtp-id" when "anymail_id" 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** SendGrid will accept *and send* just about anything as a message's :attr:`from_email`. (And email protocols are diff --git a/tests/test_sendgrid_backend.py b/tests/test_sendgrid_backend.py index b85673ff..823d1099 100644 --- a/tests/test_sendgrid_backend.py +++ b/tests/test_sendgrid_backend.py @@ -187,7 +187,7 @@ def test_email_message(self): self.assertEqual( 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( data["headers"], { @@ -243,7 +243,8 @@ def test_extra_headers(self): # Reply-To must be moved to separate param self.assertNotIn("Reply-To", data["headers"]) 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): @@ -252,26 +253,6 @@ def test_extra_headers_serialization_error(self): self.message.send() def test_reply_to(self): - self.message.reply_to = ['"Reply recipient" '], cc=["cc1@sink.sendgrid.net", "Copy 2 "], bcc=["bcc1@sink.sendgrid.net", "Blind Copy 2 "], - # v3 only supports single reply-to: - reply_to=['"Reply, with comma" '], + reply_to=['"Reply, with comma" ', "reply2@example.com"], headers={"X-Anymail-Test": "value", "X-Anymail-Count": 3}, metadata={"meta1": "simple string", "meta2": 2}, send_at=send_at,