SendGrid: add merge_metadata

Add support in SendGrid backend for per-recipient metadata.
This commit is contained in:
Janne Thoft
2019-02-21 21:44:53 +01:00
committed by Mike Edmunds
parent 412a1b78c6
commit 85dce5fd6a
3 changed files with 165 additions and 4 deletions

View File

@@ -77,6 +77,7 @@ class SendGridPayload(RequestsPayload):
self.merge_field_format = backend.merge_field_format
self.merge_data = None # late-bound per-recipient data
self.merge_global_data = None
self.merge_metadata = None
http_headers = kwargs.pop('headers', {})
http_headers['Authorization'] = 'Bearer %s' % backend.api_key
@@ -101,6 +102,7 @@ class SendGridPayload(RequestsPayload):
if self.generate_message_id:
self.set_anymail_id()
self.build_merge_data()
self.build_merge_metadata()
if not self.data["headers"]:
del self.data["headers"] # don't send empty headers
@@ -204,6 +206,28 @@ class SendGridPayload(RequestsPayload):
"Search SENDGRID_MERGE_FIELD_FORMAT in the Anymail docs for more info.",
AnymailWarning)
def build_merge_metadata(self):
if self.merge_metadata is None:
return
if self.merge_data is None:
# Burst apart each to-email in personalizations[0] into a separate
# personalization, and add merge_metadata for that recipient
assert len(self.data["personalizations"]) == 1
base_personalizations = self.data["personalizations"].pop()
to_list = base_personalizations.pop("to") # {email, name?} for each message.to
for recipient in to_list:
personalization = base_personalizations.copy() # captures cc, bcc, and any esp_extra
personalization["to"] = [recipient]
self.data["personalizations"].append(personalization)
for personalization in self.data["personalizations"]:
recipient_email = personalization["to"][0]["email"]
recipient_metadata = self.merge_metadata.get(recipient_email)
if recipient_metadata:
recipient_custom_args = self.transform_metadata(recipient_metadata)
personalization["custom_args"] = recipient_custom_args
#
# Payload construction
#
@@ -296,11 +320,14 @@ class SendGridPayload(RequestsPayload):
self.data.setdefault("attachments", []).append(att)
def set_metadata(self, metadata):
self.data["custom_args"] = self.transform_metadata(metadata)
def transform_metadata(self, metadata):
# SendGrid requires custom_args values to be strings -- not integers.
# (And issues the cryptic error {"field": null, "message": "Bad Request", "help": null}
# if they're not.)
# We'll stringify ints and floats; anything else is the caller's responsibility.
self.data["custom_args"] = {
return {
k: str(v) if isinstance(v, BASIC_NUMERIC_TYPES) else v
for k, v in metadata.items()
}
@@ -344,6 +371,12 @@ class SendGridPayload(RequestsPayload):
# template type and merge_field_format.
self.merge_global_data = merge_global_data
def set_merge_metadata(self, merge_metadata):
# Becomes personalizations[...]['custom_args'] in
# build_merge_data, after we know recipients, template type,
# and merge_field_format.
self.merge_metadata = merge_metadata
def set_esp_extra(self, extra):
self.merge_field_format = extra.pop("merge_field_format", self.merge_field_format)
self.use_dynamic_template = extra.pop("use_dynamic_template", self.use_dynamic_template)