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
This commit is contained in:
Mike Edmunds
2020-11-28 18:02:59 -08:00
committed by GitHub
parent a7ea862ff1
commit 8c1749c6f3
5 changed files with 30 additions and 22 deletions

View File

@@ -25,6 +25,20 @@ Release history
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
.. This extra heading level keeps the ToC from becoming unmanageably long .. 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 v8.1
---- ----

View File

@@ -117,10 +117,8 @@ class SparkPostPayload(RequestsPayload):
"recipients": [], "recipients": [],
} }
def set_from_email_list(self, emails): def set_from_email(self, email):
# SparkPost supports multiple From email addresses, self.data["content"]["from"] = email.address
# as a single comma-separated string
self.data["content"]["from"] = ", ".join(email.address for email in emails)
def set_to(self, emails): def set_to(self, emails):
if emails: if emails:

View File

@@ -213,6 +213,18 @@ Limitations and quirks
use only the domain portion and substitute its own encoded mailbox before use only the domain portion and substitute its own encoded mailbox before
the @. 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: .. _sparkpost-templates:

View File

@@ -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 django.utils.timezone import get_fixed_timezone, override as override_current_timezone, utc
from anymail.exceptions import ( from anymail.exceptions import (
AnymailAPIError, AnymailConfigurationError, AnymailInvalidAddress, AnymailRecipientsRefused, AnymailAPIError, AnymailConfigurationError, AnymailRecipientsRefused,
AnymailSerializationError, AnymailUnsupportedFeature) AnymailSerializationError, AnymailUnsupportedFeature)
from anymail.message import attach_inline_image_file 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" <second@example.com>'
self.message.send()
data = self.get_api_call_json()
self.assertEqual(data["content"]["from"],
'first@example.com, "From, also" <second@example.com>')
# 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 <from@example.com>'
with self.assertRaises(AnymailInvalidAddress):
self.message.send()
def test_api_failure(self): def test_api_failure(self):
self.set_mock_response(status_code=400) self.set_mock_response(status_code=400)
with self.assertRaisesMessage(AnymailAPIError, "SparkPost API response 400"): with self.assertRaisesMessage(AnymailAPIError, "SparkPost API response 400"):

View File

@@ -59,9 +59,7 @@ class SparkPostBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
message = AnymailMessage( message = AnymailMessage(
subject="Anymail all-options integration test", subject="Anymail all-options integration test",
body="This is the text body", body="This is the text body",
# Caution: although SparkPost allows multiple From addresses, from_email="Test From <test@test-sp.anymail.info>",
# many ISPs will just bounce email that tries it...
from_email="Test From <test@test-sp.anymail.info>, also-from@test-sp.anymail.info",
to=["to1@test.sink.sparkpostmail.com", "Recipient 2 <to2@test.sink.sparkpostmail.com>"], to=["to1@test.sink.sparkpostmail.com", "Recipient 2 <to2@test.sink.sparkpostmail.com>"],
# Limit the live b/cc's to avoid running through our small monthly allowance: # Limit the live b/cc's to avoid running through our small monthly allowance:
# cc=["cc1@test.sink.sparkpostmail.com", "Copy 2 <cc2@test.sink.sparkpostmail.com>"], # cc=["cc1@test.sink.sparkpostmail.com", "Copy 2 <cc2@test.sink.sparkpostmail.com>"],