From f60013c580517daafd1240b7f3e9a8cc2697bd0d Mon Sep 17 00:00:00 2001 From: Josh Kersey Date: Thu, 24 May 2018 12:46:24 -0500 Subject: [PATCH 1/5] modified custom_arg message_id for compatibility with API v3 --- anymail/backends/sendgrid.py | 6 ++---- anymail/webhooks/sendgrid.py | 5 ++++- tests/test_sendgrid_backend.py | 6 +++--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/anymail/backends/sendgrid.py b/anymail/backends/sendgrid.py index fe4c3c23..ca232827 100644 --- a/anymail/backends/sendgrid.py +++ b/anymail/backends/sendgrid.py @@ -114,10 +114,8 @@ def ensure_message_id(self): self.data["headers"]["Message-ID"] = self.make_message_id() self.message_id = self.data["headers"]["Message-ID"] - # Workaround for missing message ID (smtp-id) in SendGrid engagement events - # (click and open tracking): because unique_args get merged into the raw event - # record, we can supply the 'smtp-id' field for any events missing it. - self.data.setdefault("custom_args", {})["smtp-id"] = self.message_id + # Set anymail-id to track our custom message ID + self.data.setdefault("custom_args", {})["anymail-id"] = self.message_id def make_message_id(self): """Returns a Message-ID that could be used for this payload diff --git a/anymail/webhooks/sendgrid.py b/anymail/webhooks/sendgrid.py index 13f8384f..7a022fc6 100644 --- a/anymail/webhooks/sendgrid.py +++ b/anymail/webhooks/sendgrid.py @@ -69,10 +69,12 @@ def esp_to_anymail_event(self, esp_event): else: metadata = {} + anymail_id = esp_event.get('anymail-id', None) + smtp_id = esp_event.get('smtp-id', None) return AnymailTrackingEvent( event_type=event_type, timestamp=timestamp, - message_id=esp_event.get('smtp-id', None), + message_id=anymail_id if anymail_id and anymail_id != smtp_id else smtp_id, # backwards compatibility event_id=esp_event.get('sg_event_id', None), recipient=esp_event.get('email', None), reject_reason=reject_reason, @@ -86,6 +88,7 @@ def esp_to_anymail_event(self, esp_event): # Known keys in SendGrid events (used to recover metadata above) sendgrid_event_keys = { + 'anymail-id', 'asm_group_id', 'attempt', # MTA deferred count 'category', diff --git a/tests/test_sendgrid_backend.py b/tests/test_sendgrid_backend.py index 6a3c3713..8bf633f1 100644 --- a/tests/test_sendgrid_backend.py +++ b/tests/test_sendgrid_backend.py @@ -58,7 +58,7 @@ def test_send_mail(self): # make sure backend assigned a Message-ID for event tracking self.assertRegex(data['headers']['Message-ID'], r'\<.+@sender\.example\.com\>') # id uses from_email's domain # make sure we added the Message-ID to custom_args for event notification - self.assertEqual(data['headers']['Message-ID'], data['custom_args']['smtp-id']) + self.assertEqual(data['headers']['Message-ID'], data['custom_args']['anymail-id']) def test_name_addr(self): """Make sure RFC2822 name-addr format (with display-name) is allowed @@ -120,7 +120,7 @@ def test_email_message(self): }) # make sure custom Message-ID also added to custom_args self.assertEqual(data['custom_args'], { - 'smtp-id': "", + 'anymail-id': "", }) def test_html_message(self): @@ -345,7 +345,7 @@ def test_metadata(self): self.message.metadata = {'user_id': "12345", 'items': 6, 'float': 98.6, 'long': longtype(123)} self.message.send() data = self.get_api_call_json() - data['custom_args'].pop('smtp-id', None) # remove Message-ID we added as tracking workaround + data['custom_args'].pop('anymail-id', None) # remove Message-ID we added as tracking workaround self.assertEqual(data['custom_args'], {'user_id': "12345", 'items': "6", # int converted to a string, 'float': "98.6", # float converted to a string (watch binary rounding!) From 8c3c300ec36228f2db3baa974fb40a331a3eb63c Mon Sep 17 00:00:00 2001 From: Josh Kersey Date: Tue, 29 May 2018 13:41:05 -0500 Subject: [PATCH 2/5] added uuid to sendgrid tracking as anymail_id; simplified sendgrid message_id functions --- anymail/backends/sendgrid.py | 27 ++++++--------------------- anymail/webhooks/sendgrid.py | 6 ++---- tests/test_sendgrid_backend.py | 14 +++++--------- tests/test_sendgrid_webhooks.py | 16 ++++++++-------- tests/utils.py | 9 +++++++++ 5 files changed, 30 insertions(+), 42 deletions(-) diff --git a/anymail/backends/sendgrid.py b/anymail/backends/sendgrid.py index ca232827..0f2ff5cb 100644 --- a/anymail/backends/sendgrid.py +++ b/anymail/backends/sendgrid.py @@ -1,3 +1,4 @@ +import uuid from email.utils import quote as rfc822_quote import warnings @@ -99,7 +100,7 @@ def serialize_data(self): """Performs any necessary serialization on self.data, and returns the result.""" if self.generate_message_id: - self.ensure_message_id() + self.set_anymail_id() self.build_merge_data() if not self.data["headers"]: @@ -107,26 +108,10 @@ def serialize_data(self): return self.serialize_json(self.data) - def ensure_message_id(self): - """Ensure message has a known Message-ID for later event tracking""" - if "Message-ID" not in self.data["headers"]: - # Only make our own if caller hasn't already provided one - self.data["headers"]["Message-ID"] = self.make_message_id() - self.message_id = self.data["headers"]["Message-ID"] - - # Set anymail-id to track our custom message ID - self.data.setdefault("custom_args", {})["anymail-id"] = self.message_id - - def make_message_id(self): - """Returns a Message-ID that could be used for this payload - - Tries to use the from_email's domain as the Message-ID's domain - """ - try: - _, domain = self.data["from"]["email"].split("@") - except (AttributeError, KeyError, TypeError, ValueError): - domain = None - return make_msgid(domain=domain) + def set_anymail_id(self): + """Ensure message has a known anymail_id for later event tracking""" + + self.data.setdefault("custom_args", {})["anymail_id"] = str(uuid.uuid4()) def build_merge_data(self): """Set personalizations[...]['substitutions'] and data['sections']""" diff --git a/anymail/webhooks/sendgrid.py b/anymail/webhooks/sendgrid.py index 7a022fc6..b8d94fe9 100644 --- a/anymail/webhooks/sendgrid.py +++ b/anymail/webhooks/sendgrid.py @@ -69,12 +69,10 @@ def esp_to_anymail_event(self, esp_event): else: metadata = {} - anymail_id = esp_event.get('anymail-id', None) - smtp_id = esp_event.get('smtp-id', None) return AnymailTrackingEvent( event_type=event_type, timestamp=timestamp, - message_id=anymail_id if anymail_id and anymail_id != smtp_id else smtp_id, # backwards compatibility + message_id=esp_event.get('anymail_id', esp_event.get('smtp-id')), # backwards compatibility event_id=esp_event.get('sg_event_id', None), recipient=esp_event.get('email', None), reject_reason=reject_reason, @@ -88,7 +86,7 @@ def esp_to_anymail_event(self, esp_event): # Known keys in SendGrid events (used to recover metadata above) sendgrid_event_keys = { - 'anymail-id', + 'anymail_id', 'asm_group_id', 'attempt', # MTA deferred count 'category', diff --git a/tests/test_sendgrid_backend.py b/tests/test_sendgrid_backend.py index 8bf633f1..8c42e6c5 100644 --- a/tests/test_sendgrid_backend.py +++ b/tests/test_sendgrid_backend.py @@ -55,10 +55,8 @@ def test_send_mail(self): self.assertEqual(data['personalizations'], [{ 'to': [{'email': "to@example.com"}], }]) - # make sure backend assigned a Message-ID for event tracking - self.assertRegex(data['headers']['Message-ID'], r'\<.+@sender\.example\.com\>') # id uses from_email's domain - # make sure we added the Message-ID to custom_args for event notification - self.assertEqual(data['headers']['Message-ID'], data['custom_args']['anymail-id']) + # make sure the backend assigned the anymail_id for event tracking and notification + self.assertUUIDIsValid(data['custom_args']['anymail_id']) def test_name_addr(self): """Make sure RFC2822 name-addr format (with display-name) is allowed @@ -119,9 +117,7 @@ def test_email_message(self): 'Message-ID': "", }) # make sure custom Message-ID also added to custom_args - self.assertEqual(data['custom_args'], { - 'anymail-id': "", - }) + self.assertUUIDIsValid(data['custom_args']['anymail_id']) def test_html_message(self): text_content = 'This is an important message.' @@ -345,7 +341,7 @@ def test_metadata(self): self.message.metadata = {'user_id': "12345", 'items': 6, 'float': 98.6, 'long': longtype(123)} self.message.send() data = self.get_api_call_json() - data['custom_args'].pop('anymail-id', None) # remove Message-ID we added as tracking workaround + data['custom_args'].pop('anymail_id', None) # remove Message-ID we added as tracking workaround self.assertEqual(data['custom_args'], {'user_id': "12345", 'items': "6", # int converted to a string, 'float': "98.6", # float converted to a string (watch binary rounding!) @@ -579,7 +575,7 @@ def test_send_attaches_anymail_status(self): sent = msg.send() self.assertEqual(sent, 1) self.assertEqual(msg.anymail_status.status, {'queued'}) - self.assertRegex(msg.anymail_status.message_id, r'\<.+@example\.com\>') # don't know exactly what it'll be + self.assertUUIDIsValid(msg.anymail_status.message_id) # don't know exactly what it'll be self.assertEqual(msg.anymail_status.recipients['to1@example.com'].status, 'queued') self.assertEqual(msg.anymail_status.recipients['to1@example.com'].message_id, msg.anymail_status.message_id) diff --git a/tests/test_sendgrid_webhooks.py b/tests/test_sendgrid_webhooks.py index ef3bb4a3..64edd405 100644 --- a/tests/test_sendgrid_webhooks.py +++ b/tests/test_sendgrid_webhooks.py @@ -23,7 +23,7 @@ def test_processed_event(self): raw_events = [{ "email": "recipient@example.com", "timestamp": 1461095246, - "smtp-id": "", + "anymail_id": "", "sg_event_id": "ZyjAM5rnQmuI1KFInHQ3Nw", "sg_message_id": "wrfRRvF7Q0GgwUo2CvDmEA.filter0425p1mdw1.13037.57168B4A1D.0", "event": "processed", @@ -57,7 +57,7 @@ def test_delivered_event(self): "event": "delivered", "email": "recipient@example.com", "timestamp": 1461095250, - "smtp-id": "" + "anymail_id": "" }] response = self.client.post('/anymail/sendgrid/tracking/', content_type='application/json', data=json.dumps(raw_events)) @@ -79,7 +79,7 @@ def test_delivered_event(self): def test_dropped_invalid_event(self): raw_events = [{ "email": "invalid@invalid", - "smtp-id": "", + "anymail_id": "", "timestamp": 1461095250, "sg_event_id": "3NPOePGOTkeM_U3fgWApfg", "sg_message_id": "filter0093p1las1.9128.5717FB8127.0", @@ -104,7 +104,7 @@ def test_dropped_invalid_event(self): def test_dropped_unsubscribed_event(self): raw_events = [{ "email": "unsubscribe@example.com", - "smtp-id": "", + "anymail_id": "", "timestamp": 1461095250, "sg_event_id": "oxy9OLwMTAy5EsuZn1qhIg", "sg_message_id": "filter0199p1las1.4745.5717FB6F5.0", @@ -137,7 +137,7 @@ def test_bounce_event(self): "event": "bounce", "email": "noreply@example.com", "timestamp": 1461095250, - "smtp-id": "", + "anymail_id": "", "type": "bounce" }] response = self.client.post('/anymail/sendgrid/tracking/', @@ -163,7 +163,7 @@ def test_deferred_event(self): "email": "recipient@example.com", "attempt": "1", "timestamp": 1461200990, - "smtp-id": "<20160421010427.2847.6797@example.com>", + "anymail_id": "<20160421010427.2847.6797@example.com>", }] response = self.client.post('/anymail/sendgrid/tracking/', content_type='application/json', data=json.dumps(raw_events)) @@ -187,7 +187,7 @@ def test_open_event(self): "ip": "66.102.6.229", "sg_event_id": "MjIwNDg5NTgtZGE3OC00NDI1LWFiMmMtMDUyZTU2ZmFkOTFm", "sg_message_id": "wrfRRvF7Q0GgwUo2CvDmEA.filter0425p1mdw1.13037.57168B4A1D.0", - "smtp-id": "<20160421010427.2847.6797@example.com>", + "anymail_id": "<20160421010427.2847.6797@example.com>", "useragent": "Mozilla/5.0 (Windows NT 5.1; rv:11.0) Gecko Firefox/11.0", "event": "open" }] @@ -211,7 +211,7 @@ def test_click_event(self): "sg_event_id": "OTdlOGUzYjctYjc5Zi00OWE4LWE4YWUtNjIxNjk2ZTJlNGVi", "sg_message_id": "_fjPjuJfRW-IPs5SuvYotg.filter0590p1mdw1.2098.57168CFC4B.0", "useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36", - "smtp-id": "<20160421010427.2847.6797@example.com>", + "anymail_id": "<20160421010427.2847.6797@example.com>", "event": "click", "url_offset": {"index": 0, "type": "html"}, "email": "recipient@example.com", diff --git a/tests/utils.py b/tests/utils.py index b16f691b..fddeb466 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -4,6 +4,7 @@ import os import re import sys +import uuid import warnings from base64 import b64decode from contextlib import contextmanager @@ -165,6 +166,14 @@ def assertEqualIgnoringHeaderFolding(self, first, second, msg=None): second = rfc822_unfold(second) self.assertEqual(first, second, msg) + def assertUUIDIsValid(self, uuid_str, version=4): + """Assert the uuid_str evaluates to a valid UUID""" + try: + uuid.UUID(uuid_str, version=version) + except (ValueError, AttributeError, TypeError): + return False + return True + # Backported from Python 3.4 class _AssertLogsContext(object): From 8bf9ffc1279250303975f53292c562ee032224e2 Mon Sep 17 00:00:00 2001 From: Josh Kersey Date: Tue, 29 May 2018 14:33:33 -0500 Subject: [PATCH 3/5] added anymail_id support to SendGrid V2 --- anymail/backends/sendgrid.py | 1 - anymail/backends/sendgrid_v2.py | 29 +++++------------------------ tests/test_sendgrid_v2_backend.py | 21 ++++++++------------- 3 files changed, 13 insertions(+), 38 deletions(-) diff --git a/anymail/backends/sendgrid.py b/anymail/backends/sendgrid.py index 0f2ff5cb..42624403 100644 --- a/anymail/backends/sendgrid.py +++ b/anymail/backends/sendgrid.py @@ -2,7 +2,6 @@ from email.utils import quote as rfc822_quote import warnings -from django.core.mail import make_msgid from requests.structures import CaseInsensitiveDict from .base_requests import AnymailRequestsBackend, RequestsPayload diff --git a/anymail/backends/sendgrid_v2.py b/anymail/backends/sendgrid_v2.py index a12ae333..dd329d40 100644 --- a/anymail/backends/sendgrid_v2.py +++ b/anymail/backends/sendgrid_v2.py @@ -1,6 +1,6 @@ +import uuid import warnings -from django.core.mail import make_msgid from requests.structures import CaseInsensitiveDict from ..exceptions import AnymailConfigurationError, AnymailRequestsAPIError, AnymailWarning @@ -99,7 +99,7 @@ def serialize_data(self): """Performs any necessary serialization on self.data, and returns the result.""" if self.generate_message_id: - self.ensure_message_id() + self.set_anymail_id() self.build_merge_data() if self.merge_data is not None: @@ -136,29 +136,10 @@ def serialize_data(self): return self.data - def ensure_message_id(self): - """Ensure message has a known Message-ID for later event tracking""" - headers = self.data["headers"] - if "Message-ID" not in headers: - # Only make our own if caller hasn't already provided one - headers["Message-ID"] = self.make_message_id() - self.message_id = headers["Message-ID"] + def set_anymail_id(self): + """Ensure message has a known anymail_id for later event tracking""" - # Workaround for missing message ID (smtp-id) in SendGrid engagement events - # (click and open tracking): because unique_args get merged into the raw event - # record, we can supply the 'smtp-id' field for any events missing it. - self.smtpapi.setdefault('unique_args', {})['smtp-id'] = self.message_id - - def make_message_id(self): - """Returns a Message-ID that could be used for this payload - - Tries to use the from_email's domain as the Message-ID's domain - """ - try: - _, domain = self.data["from"].split("@") - except (AttributeError, KeyError, TypeError, ValueError): - domain = None - return make_msgid(domain=domain) + self.smtpapi.setdefault('unique_args', {})["anymail_id"] = str(uuid.uuid4()) def build_merge_data(self): """Set smtpapi['sub'] and ['section']""" diff --git a/tests/test_sendgrid_v2_backend.py b/tests/test_sendgrid_v2_backend.py index 2f908f5a..950435e6 100644 --- a/tests/test_sendgrid_v2_backend.py +++ b/tests/test_sendgrid_v2_backend.py @@ -63,12 +63,9 @@ def test_send_mail(self): self.assertEqual(data['text'], "Here is the message.") self.assertEqual(data['from'], "from@sender.example.com") self.assertEqual(data['to'], ["to@example.com"]) - # make sure backend assigned a Message-ID for event tracking - email_headers = json.loads(data['headers']) - self.assertRegex(email_headers['Message-ID'], r'\<.+@sender\.example\.com\>') # id uses from_email's domain - # make sure we added the Message-ID to unique_args for event notification + # make sure the backend assigned the anymail_id to unique_args for event tracking and notification smtpapi = self.get_smtpapi() - self.assertEqual(email_headers['Message-ID'], smtpapi['unique_args']['smtp-id']) + self.assertUUIDIsValid(smtpapi['unique_args']['anymail_id']) @override_settings(ANYMAIL={'SENDGRID_USERNAME': 'sg_username', 'SENDGRID_PASSWORD': 'sg_password'}) def test_user_pass_auth(self): @@ -129,10 +126,9 @@ def test_email_message(self): 'Reply-To': 'another@example.com', 'X-MyHeader': 'my value', }) - # make sure custom Message-ID also added to unique_args - self.assertJSONEqual(data['x-smtpapi'], { - 'unique_args': {'smtp-id': ''} - }) + # make sure anymail_id also added to unique_args + smtpapi_json = json.loads(data['x-smtpapi']) + self.assertUUIDIsValid(smtpapi_json['unique_args']['anymail_id']) def test_html_message(self): text_content = 'This is an important message.' @@ -293,8 +289,7 @@ def test_suppress_empty_address_lists(self): self.assertNotIn('ccname', data) self.assertNotIn('bcc', data) self.assertNotIn('bccname', data) - headers = json.loads(data['headers']) - self.assertNotIn('Reply-To', headers) + self.assertNotIn('headers', data) # Test empty `to` -- but send requires at least one recipient somewhere (like cc) self.message.to = [] @@ -354,7 +349,7 @@ def test_metadata(self): self.message.metadata = {'user_id': "12345", 'items': 6} self.message.send() smtpapi = self.get_smtpapi() - smtpapi['unique_args'].pop('smtp-id', None) # remove Message-ID we added as tracking workaround + smtpapi['unique_args'].pop('anymail_id', None) # remove Message-ID we added as tracking workaround self.assertEqual(smtpapi['unique_args'], {'user_id': "12345", 'items': 6}) def test_send_at(self): @@ -565,7 +560,7 @@ def test_send_attaches_anymail_status(self): sent = msg.send() self.assertEqual(sent, 1) self.assertEqual(msg.anymail_status.status, {'queued'}) - self.assertRegex(msg.anymail_status.message_id, r'\<.+@example\.com\>') # don't know exactly what it'll be + self.assertUUIDIsValid(msg.anymail_status.message_id) self.assertEqual(msg.anymail_status.recipients['to1@example.com'].status, 'queued') self.assertEqual(msg.anymail_status.recipients['to1@example.com'].message_id, msg.anymail_status.message_id) From 71d977366179d343770906eb05e9e01d92a1f059 Mon Sep 17 00:00:00 2001 From: Josh Kersey Date: Tue, 29 May 2018 14:39:46 -0500 Subject: [PATCH 4/5] sendgrid webhook tests use UUIDs for anymail_id --- tests/test_sendgrid_webhooks.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tests/test_sendgrid_webhooks.py b/tests/test_sendgrid_webhooks.py index 64edd405..2978292e 100644 --- a/tests/test_sendgrid_webhooks.py +++ b/tests/test_sendgrid_webhooks.py @@ -23,7 +23,7 @@ def test_processed_event(self): raw_events = [{ "email": "recipient@example.com", "timestamp": 1461095246, - "anymail_id": "", + "anymail_id": "3c2f4df8-c6dd-4cd2-9b91-6582b81a0349", "sg_event_id": "ZyjAM5rnQmuI1KFInHQ3Nw", "sg_message_id": "wrfRRvF7Q0GgwUo2CvDmEA.filter0425p1mdw1.13037.57168B4A1D.0", "event": "processed", @@ -41,7 +41,7 @@ def test_processed_event(self): self.assertEqual(event.event_type, "queued") self.assertEqual(event.timestamp, datetime(2016, 4, 19, 19, 47, 26, tzinfo=utc)) self.assertEqual(event.esp_event, raw_events[0]) - self.assertEqual(event.message_id, "") + self.assertEqual(event.message_id, "3c2f4df8-c6dd-4cd2-9b91-6582b81a0349") self.assertEqual(event.event_id, "ZyjAM5rnQmuI1KFInHQ3Nw") self.assertEqual(event.recipient, "recipient@example.com") self.assertEqual(event.tags, ["tag1", "tag2"]) @@ -57,7 +57,7 @@ def test_delivered_event(self): "event": "delivered", "email": "recipient@example.com", "timestamp": 1461095250, - "anymail_id": "" + "anymail_id": "4ab185c2-0171-492f-9ce0-27de258efc99" }] response = self.client.post('/anymail/sendgrid/tracking/', content_type='application/json', data=json.dumps(raw_events)) @@ -69,7 +69,7 @@ def test_delivered_event(self): self.assertEqual(event.event_type, "delivered") self.assertEqual(event.timestamp, datetime(2016, 4, 19, 19, 47, 30, tzinfo=utc)) self.assertEqual(event.esp_event, raw_events[0]) - self.assertEqual(event.message_id, "") + self.assertEqual(event.message_id, "4ab185c2-0171-492f-9ce0-27de258efc99") self.assertEqual(event.event_id, "nOSv8m0eTQ-vxvwNwt3fZQ") self.assertEqual(event.recipient, "recipient@example.com") self.assertEqual(event.mta_response, "250 2.0.0 OK 1461095248 m143si2210036ioe.159 - gsmtp ") @@ -79,7 +79,7 @@ def test_delivered_event(self): def test_dropped_invalid_event(self): raw_events = [{ "email": "invalid@invalid", - "anymail_id": "", + "anymail_id": "c74002d9-7ccb-4f67-8b8c-766cec03c9a6", "timestamp": 1461095250, "sg_event_id": "3NPOePGOTkeM_U3fgWApfg", "sg_message_id": "filter0093p1las1.9128.5717FB8127.0", @@ -95,7 +95,7 @@ def test_dropped_invalid_event(self): self.assertIsInstance(event, AnymailTrackingEvent) self.assertEqual(event.event_type, "rejected") self.assertEqual(event.esp_event, raw_events[0]) - self.assertEqual(event.message_id, "") + self.assertEqual(event.message_id, "c74002d9-7ccb-4f67-8b8c-766cec03c9a6") self.assertEqual(event.event_id, "3NPOePGOTkeM_U3fgWApfg") self.assertEqual(event.recipient, "invalid@invalid") self.assertEqual(event.reject_reason, "invalid") @@ -104,7 +104,7 @@ def test_dropped_invalid_event(self): def test_dropped_unsubscribed_event(self): raw_events = [{ "email": "unsubscribe@example.com", - "anymail_id": "", + "anymail_id": "a36ec0f9-aabe-45c7-9a84-3e17afb5cb65", "timestamp": 1461095250, "sg_event_id": "oxy9OLwMTAy5EsuZn1qhIg", "sg_message_id": "filter0199p1las1.4745.5717FB6F5.0", @@ -120,7 +120,7 @@ def test_dropped_unsubscribed_event(self): self.assertIsInstance(event, AnymailTrackingEvent) self.assertEqual(event.event_type, "rejected") self.assertEqual(event.esp_event, raw_events[0]) - self.assertEqual(event.message_id, "") + self.assertEqual(event.message_id, "a36ec0f9-aabe-45c7-9a84-3e17afb5cb65") self.assertEqual(event.event_id, "oxy9OLwMTAy5EsuZn1qhIg") self.assertEqual(event.recipient, "unsubscribe@example.com") self.assertEqual(event.reject_reason, "unsubscribed") @@ -137,7 +137,7 @@ def test_bounce_event(self): "event": "bounce", "email": "noreply@example.com", "timestamp": 1461095250, - "anymail_id": "", + "anymail_id": "de212213-bb66-4302-8f3f-20acdb7a104e", "type": "bounce" }] response = self.client.post('/anymail/sendgrid/tracking/', @@ -149,7 +149,7 @@ def test_bounce_event(self): self.assertIsInstance(event, AnymailTrackingEvent) self.assertEqual(event.event_type, "bounced") self.assertEqual(event.esp_event, raw_events[0]) - self.assertEqual(event.message_id, "") + self.assertEqual(event.message_id, "de212213-bb66-4302-8f3f-20acdb7a104e") self.assertEqual(event.event_id, "lC0Rc-FuQmKbnxCWxX1jRQ") self.assertEqual(event.recipient, "noreply@example.com") self.assertEqual(event.mta_response, "550 5.1.1 The email account that you tried to reach does not exist.") @@ -163,7 +163,7 @@ def test_deferred_event(self): "email": "recipient@example.com", "attempt": "1", "timestamp": 1461200990, - "anymail_id": "<20160421010427.2847.6797@example.com>", + "anymail_id": "ccf83222-0d7e-4542-8beb-893122afa757", }] response = self.client.post('/anymail/sendgrid/tracking/', content_type='application/json', data=json.dumps(raw_events)) @@ -174,7 +174,7 @@ def test_deferred_event(self): self.assertIsInstance(event, AnymailTrackingEvent) self.assertEqual(event.event_type, "deferred") self.assertEqual(event.esp_event, raw_events[0]) - self.assertEqual(event.message_id, "<20160421010427.2847.6797@example.com>") + self.assertEqual(event.message_id, "ccf83222-0d7e-4542-8beb-893122afa757") self.assertEqual(event.event_id, "b_syL5UiTvWC_Ky5L6Bs5Q") self.assertEqual(event.recipient, "recipient@example.com") self.assertEqual(event.mta_response, @@ -187,7 +187,7 @@ def test_open_event(self): "ip": "66.102.6.229", "sg_event_id": "MjIwNDg5NTgtZGE3OC00NDI1LWFiMmMtMDUyZTU2ZmFkOTFm", "sg_message_id": "wrfRRvF7Q0GgwUo2CvDmEA.filter0425p1mdw1.13037.57168B4A1D.0", - "anymail_id": "<20160421010427.2847.6797@example.com>", + "anymail_id": "44920b35-3e31-478b-bb67-b4f5e0c85ebc", "useragent": "Mozilla/5.0 (Windows NT 5.1; rv:11.0) Gecko Firefox/11.0", "event": "open" }] @@ -200,7 +200,7 @@ def test_open_event(self): self.assertIsInstance(event, AnymailTrackingEvent) self.assertEqual(event.event_type, "opened") self.assertEqual(event.esp_event, raw_events[0]) - self.assertEqual(event.message_id, "<20160421010427.2847.6797@example.com>") + self.assertEqual(event.message_id, "44920b35-3e31-478b-bb67-b4f5e0c85ebc") self.assertEqual(event.event_id, "MjIwNDg5NTgtZGE3OC00NDI1LWFiMmMtMDUyZTU2ZmFkOTFm") self.assertEqual(event.recipient, "recipient@example.com") self.assertEqual(event.user_agent, "Mozilla/5.0 (Windows NT 5.1; rv:11.0) Gecko Firefox/11.0") @@ -211,7 +211,7 @@ def test_click_event(self): "sg_event_id": "OTdlOGUzYjctYjc5Zi00OWE4LWE4YWUtNjIxNjk2ZTJlNGVi", "sg_message_id": "_fjPjuJfRW-IPs5SuvYotg.filter0590p1mdw1.2098.57168CFC4B.0", "useragent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36", - "anymail_id": "<20160421010427.2847.6797@example.com>", + "anymail_id": "75de5af9-a090-4325-87f9-8c599ad66f60", "event": "click", "url_offset": {"index": 0, "type": "html"}, "email": "recipient@example.com", @@ -227,7 +227,7 @@ def test_click_event(self): self.assertIsInstance(event, AnymailTrackingEvent) self.assertEqual(event.event_type, "clicked") self.assertEqual(event.esp_event, raw_events[0]) - self.assertEqual(event.message_id, "<20160421010427.2847.6797@example.com>") + self.assertEqual(event.message_id, "75de5af9-a090-4325-87f9-8c599ad66f60") self.assertEqual(event.event_id, "OTdlOGUzYjctYjc5Zi00OWE4LWE4YWUtNjIxNjk2ZTJlNGVi") self.assertEqual(event.recipient, "recipient@example.com") self.assertEqual(event.user_agent, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36") From 8bd6f53645d9fdf77add269db9279f96a3dd1aed Mon Sep 17 00:00:00 2001 From: Josh Kersey Date: Tue, 29 May 2018 15:45:25 -0500 Subject: [PATCH 5/5] continue to set message_id on SendGridPayload --- anymail/backends/sendgrid.py | 3 ++- anymail/backends/sendgrid_v2.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/anymail/backends/sendgrid.py b/anymail/backends/sendgrid.py index 42624403..4ab3cabc 100644 --- a/anymail/backends/sendgrid.py +++ b/anymail/backends/sendgrid.py @@ -110,7 +110,8 @@ def serialize_data(self): def set_anymail_id(self): """Ensure message has a known anymail_id for later event tracking""" - self.data.setdefault("custom_args", {})["anymail_id"] = str(uuid.uuid4()) + self.message_id = str(uuid.uuid4()) + self.data.setdefault("custom_args", {})["anymail_id"] = self.message_id def build_merge_data(self): """Set personalizations[...]['substitutions'] and data['sections']""" diff --git a/anymail/backends/sendgrid_v2.py b/anymail/backends/sendgrid_v2.py index dd329d40..beff5d6e 100644 --- a/anymail/backends/sendgrid_v2.py +++ b/anymail/backends/sendgrid_v2.py @@ -139,7 +139,8 @@ def serialize_data(self): def set_anymail_id(self): """Ensure message has a known anymail_id for later event tracking""" - self.smtpapi.setdefault('unique_args', {})["anymail_id"] = str(uuid.uuid4()) + self.message_id = str(uuid.uuid4()) + self.smtpapi.setdefault('unique_args', {})["anymail_id"] = self.message_id def build_merge_data(self): """Set smtpapi['sub'] and ['section']"""