diff --git a/anymail/backends/mailgun.py b/anymail/backends/mailgun.py index 0964761..1ad518b 100644 --- a/anymail/backends/mailgun.py +++ b/anymail/backends/mailgun.py @@ -122,18 +122,8 @@ class MailgunPayload(RequestsPayload): ) def set_metadata(self, metadata): - # The Mailgun docs are a little unclear on whether to send each var as a separate v: field, - # or to send a single 'v:my-custom-data' field with a json blob of all vars. - # (https://documentation.mailgun.com/user_manual.html#attaching-data-to-messages) - # From experimentation, it seems like the first option works: for key, value in metadata.items(): - # Ensure the value is json-serializable (for Mailgun storage) - json = self.serialize_json(value) # will raise AnymailSerializationError - # Special case: a single string value should be sent bare (without quotes), - # because Mailgun will add quotes when querying the value as json. - if json.startswith('"'): # only a single string could be serialized as "... - json = value - self.data["v:%s" % key] = json + self.data["v:%s" % key] = value def set_send_at(self, send_at): # Mailgun expects RFC-2822 format dates diff --git a/tests/test_mailgun_backend.py b/tests/test_mailgun_backend.py index f272b26..47bb03a 100644 --- a/tests/test_mailgun_backend.py +++ b/tests/test_mailgun_backend.py @@ -3,7 +3,6 @@ from __future__ import unicode_literals from datetime import date, datetime -from decimal import Decimal from email.mime.base import MIMEBase from email.mime.image import MIMEImage @@ -13,7 +12,7 @@ from django.test import SimpleTestCase from django.test.utils import override_settings from django.utils.timezone import get_fixed_timezone, override as override_current_timezone -from anymail.exceptions import AnymailAPIError, AnymailSerializationError, AnymailUnsupportedFeature +from anymail.exceptions import AnymailAPIError, AnymailUnsupportedFeature from anymail.message import attach_inline_image_file from .mock_requests_backend import RequestsBackendMockAPITestCase, SessionSharingTestCasesMixin @@ -270,12 +269,13 @@ class MailgunBackendAnymailFeatureTests(MailgunBackendMockAPITestCase): """Test backend support for Anymail added features""" def test_metadata(self): - self.message.metadata = {'user_id': "12345", 'items': ['mail', 'gun']} + # Each metadata value is just a string; you can serialize your own JSON if you'd like. + # (The Mailgun docs are a little confusing on this point.) + self.message.metadata = {'user_id': "12345", 'items': '["mail","gun"]'} self.message.send() data = self.get_api_call_data() - # note values get serialized to json: - self.assertEqual(data['v:user_id'], '12345') # simple values are transmitted as-is - self.assertEqual(data['v:items'], '["mail", "gun"]') # complex values get json-serialized + self.assertEqual(data['v:user_id'], '12345') + self.assertEqual(data['v:items'], '["mail","gun"]') def test_send_at(self): utc_plus_6 = get_fixed_timezone(6 * 60) @@ -401,16 +401,8 @@ class MailgunBackendAnymailFeatureTests(MailgunBackendMockAPITestCase): self.assertEqual(self.message.anymail_status.recipients, {}) self.assertEqual(self.message.anymail_status.esp_response, mock_response) - def test_json_serialization_errors(self): - """Try to provide more information about non-json-serializable data""" - self.message.metadata = {'total': Decimal('19.99')} - with self.assertRaises(AnymailSerializationError) as cm: - self.message.send() - print(self.get_api_call_data()) - err = cm.exception - self.assertIsInstance(err, TypeError) # compatibility with json.dumps - self.assertIn("Don't know how to send this data to Mailgun", str(err)) # our added context - self.assertIn("Decimal('19.99') is not JSON serializable", str(err)) # original message + # test_json_serialization_errors: Mailgun payload isn't JSON, so we don't test this. + # (Anything that requests can serialize as a form field will work with Mailgun) class MailgunBackendRecipientsRefusedTests(MailgunBackendMockAPITestCase): diff --git a/tests/test_mailgun_integration.py b/tests/test_mailgun_integration.py index 4cdb971..7bc1516 100644 --- a/tests/test_mailgun_integration.py +++ b/tests/test_mailgun_integration.py @@ -111,7 +111,7 @@ class MailgunBackendIntegrationTests(SimpleTestCase, AnymailTestMixin): reply_to=["reply1@example.com", "Reply 2 "], headers={"X-Anymail-Test": "value"}, - metadata={"meta1": "simple string", "meta2": 2, "meta3": {"complex": "value"}}, + metadata={"meta1": "simple string", "meta2": 2}, send_at=send_at, tags=["tag 1", "tag 2"], track_clicks=False, @@ -136,9 +136,7 @@ class MailgunBackendIntegrationTests(SimpleTestCase, AnymailTestMixin): event = events.pop() self.assertCountEqual(event["tags"], ["tag 1", "tag 2"]) # don't care about order self.assertEqual(event["user-variables"], - {"meta1": "simple string", - "meta2": "2", # numbers become strings - "meta3": '{"complex": "value"}'}) # complex values become json + {"meta1": "simple string", "meta2": "2"}) # all metadata values become strings self.assertEqual(event["message"]["scheduled-for"], send_at_timestamp) self.assertCountEqual(event["message"]["recipients"],