From b664ee3dbcf43bdbedfc52a978fa090af50a2708 Mon Sep 17 00:00:00 2001 From: medmunds Date: Wed, 22 Jun 2016 16:54:40 -0700 Subject: [PATCH] SparkPost: work around json recipients problem python-sparkpost generates a transmissions.send payload which is now considered invalid by the API, if you try to use both `cc` (or `bcc`) and the `recipients` dict structure required for merge_data. [Anymail had been generating that recipients dict structure in all cases, for simplicity. Sometime between 2016-06-07 and 2016-06-22, SparkPost began rejecting that if it appeared in the `header_to` constructed by python-sparkpost.] --- anymail/backends/sparkpost.py | 23 ++++++++++++++--------- tests/test_sparkpost_backend.py | 12 +++--------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/anymail/backends/sparkpost.py b/anymail/backends/sparkpost.py index ebaffa5..83605ec 100644 --- a/anymail/backends/sparkpost.py +++ b/anymail/backends/sparkpost.py @@ -87,15 +87,20 @@ class SparkPostPayload(BasePayload): def get_api_params(self): # Compose recipients param from to_emails and merge_data (if any) recipients = [] - for email in self.to_emails: - rcpt = {'address': {'email': email.email}} - if email.name: - rcpt['address']['name'] = email.name - try: - rcpt['substitution_data'] = self.merge_data[email.email] - except KeyError: - pass # no merge_data or none for this recipient - recipients.append(rcpt) + if len(self.merge_data) > 0: + # Build JSON recipient structures + for email in self.to_emails: + rcpt = {'address': {'email': email.email}} + if email.name: + rcpt['address']['name'] = email.name + try: + rcpt['substitution_data'] = self.merge_data[email.email] + except KeyError: + pass # no merge_data or none for this recipient + recipients.append(rcpt) + else: + # Just use simple recipients list + recipients = [email.address for email in self.to_emails] if recipients: self.params['recipients'] = recipients diff --git a/tests/test_sparkpost_backend.py b/tests/test_sparkpost_backend.py index 4cfd356..942f229 100644 --- a/tests/test_sparkpost_backend.py +++ b/tests/test_sparkpost_backend.py @@ -99,7 +99,7 @@ class SparkPostBackendStandardEmailTests(SparkPostBackendMockAPITestCase): self.assertEqual(params['subject'], "Subject here") self.assertEqual(params['text'], "Here is the message.") self.assertEqual(params['from_email'], "from@example.com") - self.assertEqual(params['recipients'], [{'address': {'email': "to@example.com"}}]) + self.assertEqual(params['recipients'], ["to@example.com"]) self.assertEqual(self.get_send_api_key(), 'test_api_key') @@ -118,10 +118,7 @@ class SparkPostBackendStandardEmailTests(SparkPostBackendMockAPITestCase): params = self.get_send_params() self.assertEqual(params['from_email'], "From Name ") # We pre-parse the to-field emails (merge_data also gets attached there): - self.assertEqual(params['recipients'], [ - {'address': {'email': 'to1@example.com', 'name': 'Recipient #1'}}, - {'address': {'email': 'to2@example.com'}} - ]) + self.assertEqual(params['recipients'], ['Recipient #1 ', 'to2@example.com']) # We let python-sparkpost parse the other email fields: self.assertEqual(params['cc'], ['Carbon Copy ', 'cc2@example.com']) self.assertEqual(params['bcc'], ['Blind Copy ', 'bcc2@example.com']) @@ -141,10 +138,7 @@ class SparkPostBackendStandardEmailTests(SparkPostBackendMockAPITestCase): self.assertEqual(params['subject'], "Subject") self.assertEqual(params['text'], "Body goes here") self.assertEqual(params['from_email'], "from@example.com") - self.assertEqual(params['recipients'], [ - {'address': {'email': 'to1@example.com'}}, - {'address': {'email': 'to2@example.com', 'name': 'Also To'}} - ]) + self.assertEqual(params['recipients'], ['to1@example.com', 'Also To ']) self.assertEqual(params['bcc'], ['bcc1@example.com', 'Also BCC ']) self.assertEqual(params['cc'], ['cc1@example.com', 'Also CC ']) self.assertEqual(params['custom_headers'], {