From 8c1749c6f34bd9630d240d2c8b0421a5802f92c5 Mon Sep 17 00:00:00 2001 From: Mike Edmunds Date: Sat, 28 Nov 2020 18:02:59 -0800 Subject: [PATCH] SparkPost: drop support for multiple from_email (#213) SparkPost's API no longer allows this, and now returns a confusing error message about return_path. (Not treating as a breaking change in Anymail, because the breaking change was in the SparkPost API. This just improves the error message in the unlikely event anyone is trying to use this feature.) Closes #212 --- CHANGELOG.rst | 14 ++++++++++++++ anymail/backends/sparkpost.py | 6 ++---- docs/esps/sparkpost.rst | 12 ++++++++++++ tests/test_sparkpost_backend.py | 16 +--------------- tests/test_sparkpost_integration.py | 4 +--- 5 files changed, 30 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index bd1526e..1eff486 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -25,6 +25,20 @@ Release history ^^^^^^^^^^^^^^^ .. This extra heading level keeps the ToC from becoming unmanageably long +vNext +----- + +*Unreleased changes* + +Fixes +~~~~~ + +* **SparkPost:** Drop support for multiple `from_email` addresses. SparkPost has + started issuing a cryptic "No sending domain specified" error for this case; with + this fix, Anymail will now treat it as an unsupported feature. + + + v8.1 ---- diff --git a/anymail/backends/sparkpost.py b/anymail/backends/sparkpost.py index 988cc3d..0dc7f8c 100644 --- a/anymail/backends/sparkpost.py +++ b/anymail/backends/sparkpost.py @@ -117,10 +117,8 @@ class SparkPostPayload(RequestsPayload): "recipients": [], } - def set_from_email_list(self, emails): - # SparkPost supports multiple From email addresses, - # as a single comma-separated string - self.data["content"]["from"] = ", ".join(email.address for email in emails) + def set_from_email(self, email): + self.data["content"]["from"] = email.address def set_to(self, emails): if emails: diff --git a/docs/esps/sparkpost.rst b/docs/esps/sparkpost.rst index ec5f94a..404500f 100644 --- a/docs/esps/sparkpost.rst +++ b/docs/esps/sparkpost.rst @@ -213,6 +213,18 @@ Limitations and quirks use only the domain portion and substitute its own encoded mailbox before the @. +**Multiple from_email addresses** + Prior to November, 2020, SparkPost supporting sending messages with multiple + *From* addresses. (This is technically allowed by email specs, but many + ISPs bounce such messages.) Anymail v8.1 and earlier will pass multiple + ``from_email`` addresses to SparkPost's API. + + SparkPost has since dropped support for more than one from address, and now issues + error code 7001 "No sending domain specified". To avoid confusion, Anymail v8.2 + treats multiple from addresses as an unsupported feature in the SparkPost backend. + + .. versionchanged:: 8.2 + .. _sparkpost-templates: diff --git a/tests/test_sparkpost_backend.py b/tests/test_sparkpost_backend.py index 3aff660..7474bc9 100644 --- a/tests/test_sparkpost_backend.py +++ b/tests/test_sparkpost_backend.py @@ -10,7 +10,7 @@ from django.test import override_settings, tag from django.utils.timezone import get_fixed_timezone, override as override_current_timezone, utc from anymail.exceptions import ( - AnymailAPIError, AnymailConfigurationError, AnymailInvalidAddress, AnymailRecipientsRefused, + AnymailAPIError, AnymailConfigurationError, AnymailRecipientsRefused, AnymailSerializationError, AnymailUnsupportedFeature) from anymail.message import attach_inline_image_file @@ -318,20 +318,6 @@ class SparkPostBackendStandardEmailTests(SparkPostBackendMockAPITestCase): }, }]) - def test_multiple_from_emails(self): - """SparkPost supports multiple addresses in from_email""" - self.message.from_email = 'first@example.com, "From, also" ' - self.message.send() - data = self.get_api_call_json() - self.assertEqual(data["content"]["from"], - 'first@example.com, "From, also" ') - - # Make sure the far-more-likely scenario of a single from_email - # with an unquoted display-name issues a reasonable error: - self.message.from_email = 'Unquoted, display-name ' - with self.assertRaises(AnymailInvalidAddress): - self.message.send() - def test_api_failure(self): self.set_mock_response(status_code=400) with self.assertRaisesMessage(AnymailAPIError, "SparkPost API response 400"): diff --git a/tests/test_sparkpost_integration.py b/tests/test_sparkpost_integration.py index 3d9a8d3..013c936 100644 --- a/tests/test_sparkpost_integration.py +++ b/tests/test_sparkpost_integration.py @@ -59,9 +59,7 @@ class SparkPostBackendIntegrationTests(AnymailTestMixin, SimpleTestCase): message = AnymailMessage( subject="Anymail all-options integration test", body="This is the text body", - # Caution: although SparkPost allows multiple From addresses, - # many ISPs will just bounce email that tries it... - from_email="Test From , also-from@test-sp.anymail.info", + from_email="Test From ", to=["to1@test.sink.sparkpostmail.com", "Recipient 2 "], # Limit the live b/cc's to avoid running through our small monthly allowance: # cc=["cc1@test.sink.sparkpostmail.com", "Copy 2 "],