diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b599f25..ede16a7 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -33,6 +33,8 @@ vNext Fixes ~~~~~ +* **Postmark:** Fix API error when sending with template to single recipient. + (Thanks to `@jc-ee`_ for finding and fixing the issue.) * **SendGrid:** Allow non-batch template send to multiple recipients when `merge_global_data` is set without `merge_data`. (Broken in v6.0. Thanks to `@vgrebenschikov`_ for the bug report.) @@ -1026,6 +1028,7 @@ Features .. _@ewingrj: https://github.com/ewingrj .. _@fdemmer: https://github.com/fdemmer .. _@janneThoft: https://github.com/janneThoft +.. _@jc-ee: https://github.com/jc-ee .. _@joshkersey: https://github.com/joshkersey .. _@Lekensteyn: https://github.com/Lekensteyn .. _@lewistaylor: https://github.com/lewistaylor diff --git a/anymail/backends/postmark.py b/anymail/backends/postmark.py index 58a9a65..2cae34c 100644 --- a/anymail/backends/postmark.py +++ b/anymail/backends/postmark.py @@ -179,12 +179,19 @@ class PostmarkPayload(RequestsPayload): return params def serialize_data(self): - data = self.data api_endpoint = self.get_api_endpoint() - if api_endpoint == "email/batchWithTemplates": + if api_endpoint == "email": + data = self.data + elif api_endpoint == "email/batchWithTemplates": data = {"Messages": [self.data_for_recipient(to) for to in self.to_emails]} elif api_endpoint == "email/batch": data = [self.data_for_recipient(to) for to in self.to_emails] + elif api_endpoint == "email/withTemplate/": + assert len(self.to_emails) == 1 + data = self.data_for_recipient(self.to_emails[0]) + else: + raise AssertionError("PostmarkPayload.serialize_data missing" + " case for api_endpoint %r" % api_endpoint) return self.serialize_json(data) def data_for_recipient(self, to): diff --git a/tests/test_postmark_backend.py b/tests/test_postmark_backend.py index 3629171..3c28a18 100644 --- a/tests/test_postmark_backend.py +++ b/tests/test_postmark_backend.py @@ -450,6 +450,34 @@ class PostmarkBackendAnymailFeatureTests(PostmarkBackendMockAPITestCase): self.assertEqual(recipients['bob@example.com'].status, 'sent') self.assertEqual(recipients['bob@example.com'].message_id, 'e2ecbbfc-fe12-463d-b933-9fe22915106d') + def test_merge_data_single_recipient(self): + self.set_mock_response(raw=self._mock_batch_response) + message = AnymailMessage( + from_email='from@example.com', + template_id=1234567, # Postmark only supports merge_data content in a template + to=['alice@example.com'], + merge_data={ + 'alice@example.com': {'name': "Alice", 'group': "Developers"}, + 'nobody@example.com': {'name': "Not a recipient for this message"}, + }, + merge_global_data={'group': "Users", 'site': "ExampleCo"} + ) + message.send() + + self.assert_esp_called('/email/withTemplate/') + data = self.get_api_call_json() + + self.assertEqual(data, { + "From": "from@example.com", + "To": "alice@example.com", + "TemplateId": 1234567, + "TemplateModel": {"name": "Alice", "group": "Developers", "site": "ExampleCo"}, + }) + + recipients = message.anymail_status.recipients + self.assertEqual(recipients['alice@example.com'].status, 'sent') + self.assertEqual(recipients['alice@example.com'].message_id, 'b7bc2f4a-e38e-4336-af7d-e6c392c2f817') + def test_merge_data_no_template(self): # merge_data={} can be used to force batch sending without a template self.set_mock_response(raw=self._mock_batch_response)