mirror of
https://github.com/pacnpal/django-anymail.git
synced 2025-12-20 11:51:05 -05:00
SendGrid: change message_id from Message-ID/smtp-id to UUID anymail_id
SendGrid does not always correctly provide the sent Message-ID header value to a tracking webhook's smtp-id field, making it unreliable to use for Anymail's `message_id`. Instead, generate a UUID `message_id` for Anymail tracking, and pass it from send to webhooks in SendGrid custom args as anymail_id. Webhooks will fall back to smtp-id for compatibility with previously-sent messages that didn't have an anymail_id custom arg. Fixes #108
This commit is contained in:
committed by
Mike Edmunds
parent
51d2a404c0
commit
d8d1407c61
@@ -1,7 +1,7 @@
|
||||
import uuid
|
||||
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
|
||||
@@ -99,7 +99,7 @@ class SendGridPayload(RequestsPayload):
|
||||
"""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,28 +107,11 @@ class SendGridPayload(RequestsPayload):
|
||||
|
||||
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"]
|
||||
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.data.setdefault("custom_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"]["email"].split("@")
|
||||
except (AttributeError, KeyError, TypeError, ValueError):
|
||||
domain = None
|
||||
return make_msgid(domain=domain)
|
||||
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']"""
|
||||
|
||||
@@ -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 @@ class SendGridPayload(RequestsPayload):
|
||||
"""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,11 @@ class SendGridPayload(RequestsPayload):
|
||||
|
||||
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.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']"""
|
||||
|
||||
Reference in New Issue
Block a user