Skip to content

Commit

Permalink
SparkPost: support merge_headers
Browse files Browse the repository at this point in the history
  • Loading branch information
medmunds committed Jun 20, 2024
1 parent c7449fd commit 681569b
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 0 deletions.
30 changes: 30 additions & 0 deletions anymail/backends/sparkpost.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,36 @@ def set_merge_metadata(self, merge_metadata):
if to_email in merge_metadata:
recipient["metadata"] = merge_metadata[to_email]

def set_merge_headers(self, merge_headers):
def header_var(field):
return "Header__" + field.title().replace("-", "_")

merge_header_fields = set()

for recipient in self.data["recipients"]:
to_email = recipient["address"]["email"]
if to_email in merge_headers:
recipient_headers = merge_headers[to_email]
recipient.setdefault("substitution_data", {}).update(
{header_var(key): value for key, value in recipient_headers.items()}
)
merge_header_fields.update(recipient_headers.keys())

if merge_header_fields:
headers = self.data.setdefault("content", {}).setdefault("headers", {})
# Global substitution_data supplies defaults for defined headers:
self.data.setdefault("substitution_data", {}).update(
{
header_var(field): headers[field]
for field in merge_header_fields
if field in headers
}
)
# Indirect merge_headers through substitution_data:
headers.update(
{field: "{{%s}}" % header_var(field) for field in merge_header_fields}
)

def set_send_at(self, send_at):
try:
start_time = send_at.replace(microsecond=0).isoformat()
Expand Down
52 changes: 52 additions & 0 deletions tests/test_sparkpost_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,58 @@ def test_merge_metadata(self):
)
self.assertEqual(data["metadata"], {"notification_batch": "zx912"})

def test_merge_headers(self):
self.set_mock_result(accepted=2)
self.message.to = ["[email protected]", "Bob <[email protected]>"]
self.message.extra_headers = {
"X-Custom-1": "custom 1",
"X-Custom-2": "custom 2 (default)",
}
self.message.merge_headers = {
"[email protected]": {
"X-Custom-2": "custom 2 alice",
"X-Custom-3": "custom 3 alice",
},
"[email protected]": {"X-Custom-2": "custom 2 bob"},
}

self.message.send()
data = self.get_api_call_json()
recipients = data["recipients"]
self.assertEqual(len(recipients), 2)
self.assertEqual(recipients[0]["address"]["email"], "[email protected]")
self.assertEqual(
recipients[0]["substitution_data"],
{
"Header__X_Custom_2": "custom 2 alice",
"Header__X_Custom_3": "custom 3 alice",
},
)
self.assertEqual(recipients[1]["address"]["email"], "[email protected]")
self.assertEqual(
recipients[1]["substitution_data"],
{
"Header__X_Custom_2": "custom 2 bob",
},
)
# Indirect merge_headers through template substitutions:
self.assertEqual(
data["content"]["headers"],
{
"X-Custom-1": "custom 1", # (not a merge_header, value unchanged)
"X-Custom-2": "{{Header__X_Custom_2}}",
"X-Custom-3": "{{Header__X_Custom_3}}",
},
)
# Defaults for merge_headers in global substitution_data:
self.assertEqual(
data["substitution_data"],
{
"Header__X_Custom_2": "custom 2 (default)",
# No default specified for X-Custom-3; SparkPost will use empty string
},
)

def test_default_omits_options(self):
"""Make sure by default we don't send any ESP-specific options.
Expand Down
13 changes: 13 additions & 0 deletions tests/test_sparkpost_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,19 @@ def test_merge_data(self):
"[email protected]": {"value": "two"},
},
merge_global_data={"global": "global_value"},
merge_metadata={
"[email protected]": {"meta1": "one"},
"[email protected]": {"meta1": "two"},
},
headers={
"X-Custom": "custom header default",
},
merge_headers={
# (Note that SparkPost doesn't support custom List-Unsubscribe headers)
"[email protected]": {
"X-Custom": "custom header one",
},
},
)
message.send()
recipient_status = message.anymail_status.recipients
Expand Down

0 comments on commit 681569b

Please sign in to comment.