From 985143b2346208242994decd92b905d5ab9dd934 Mon Sep 17 00:00:00 2001 From: medmunds Date: Fri, 11 Sep 2020 10:58:40 -0700 Subject: [PATCH] SparkPost: add subaccount support --- CHANGELOG.rst | 6 ++++-- anymail/backends/sparkpost.py | 4 ++++ docs/esps/sparkpost.rst | 19 +++++++++++++++++++ tests/test_sparkpost_backend.py | 14 ++++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8bea60e..c135274 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -69,8 +69,10 @@ Breaking changes Features ~~~~~~~~ -* **SparkPost:** Add support for AMP for Email, via - ``message.attach_alternative("...AMPHTML content...", "text/x-amp-html")``. +* **SparkPost:** Add support for subaccounts (new ``"SPARKPOST_SUBACCOUNT"`` Anymail + setting), AMP for Email (via ``message.attach_alternative(..., "text/x-amp-html")``), + and A/B testing and other SparkPost sending features (via ``esp_extra``). (See + `docs `__.) v7.2.1 diff --git a/anymail/backends/sparkpost.py b/anymail/backends/sparkpost.py index e4c0456..988cc3d 100644 --- a/anymail/backends/sparkpost.py +++ b/anymail/backends/sparkpost.py @@ -15,6 +15,8 @@ class EmailBackend(AnymailRequestsBackend): """Init options from Django settings""" self.api_key = get_anymail_setting('api_key', esp_name=self.esp_name, kwargs=kwargs, allow_bare=True) + self.subaccount = get_anymail_setting('subaccount', esp_name=self.esp_name, + kwargs=kwargs, default=None) api_url = get_anymail_setting('api_url', esp_name=self.esp_name, kwargs=kwargs, default="https://api.sparkpost.com/api/v1/") if not api_url.endswith("/"): @@ -57,6 +59,8 @@ class SparkPostPayload(RequestsPayload): 'Authorization': backend.api_key, 'Content-Type': 'application/json', } + if backend.subaccount is not None: + http_headers['X-MSYS-SUBACCOUNT'] = backend.subaccount self.recipients = [] # all recipients, for backend parse_recipient_status self.cc_and_bcc = [] # for _finalize_recipients super().__init__(message, defaults, backend, headers=http_headers, *args, **kwargs) diff --git a/docs/esps/sparkpost.rst b/docs/esps/sparkpost.rst index 73088be..d022692 100644 --- a/docs/esps/sparkpost.rst +++ b/docs/esps/sparkpost.rst @@ -63,6 +63,25 @@ nor ``ANYMAIL_SPARKPOST_API_KEY`` is set. .. _SparkPost account API keys: https://app.sparkpost.com/account/credentials +.. setting:: ANYMAIL_SPARKPOST_SUBACCOUNT + +.. rubric:: SPARKPOST_SUBACCOUNT + +.. versionadded:: 8.0 + +An optional `SparkPost subaccount`_ numeric id. This can be used, along with the API key +for the master account, to send mail on behalf of a subaccount. (Do not set this when +using a subaccount's own API key.) + +Like all Anymail settings, you can include this in the global settings.py ANYMAIL dict +to apply to all sends, or supply it as a :func:`~django.core.mail.get_connection` +keyword parameter (``connection = get_connection(subaccount=123)``) to send a particular +message with a subaccount. See :ref:`multiple-backends` for more information on using +connections. + +.. _SparkPost subaccount: https://www.sparkpost.com/docs/user-guide/subaccounts/ + + .. setting:: ANYMAIL_SPARKPOST_API_URL .. rubric:: SPARKPOST_API_URL diff --git a/tests/test_sparkpost_backend.py b/tests/test_sparkpost_backend.py index 5a1a5d6..3aff660 100644 --- a/tests/test_sparkpost_backend.py +++ b/tests/test_sparkpost_backend.py @@ -689,3 +689,17 @@ class SparkPostBackendConfigurationTests(SparkPostBackendMockAPITestCase): mail.send_mail('Subject', 'Message', 'from@example.com', ['to@example.com'], connection=connection) self.assert_esp_called("https://api.sparkpost.com/api/labs/transmissions/") + + def test_subaccount(self): + # A likely use case is supplying subaccount for a particular message. + # (For all messages, just set SPARKPOST_SUBACCOUNT in ANYMAIL settings.) + connection = mail.get_connection(subaccount=123) + mail.send_mail('Subject', 'Message', 'from@example.com', ['to@example.com'], + connection=connection) + headers = self.get_api_call_headers() + self.assertEqual(headers["X-MSYS-SUBACCOUNT"], 123) + + # Make sure we're not setting the header on non-subaccount sends + mail.send_mail('Subject', 'Message', 'from@example.com', ['to@example.com']) + headers = self.get_api_call_headers() + self.assertNotIn("X-MSYS-SUBACCOUNT", headers)