mirror of
https://github.com/pacnpal/django-anymail.git
synced 2025-12-20 11:51:05 -05:00
SendGrid: Improve esp_extra["personalizations"] handling.
Allow merging `esp_extra["personalizations"]` dict into other message-derived personalizations. (See comments in #120)
This commit is contained in:
@@ -39,6 +39,9 @@ Features
|
|||||||
* **SendGrid:** Support both new "dynamic" and original "legacy" transactional
|
* **SendGrid:** Support both new "dynamic" and original "legacy" transactional
|
||||||
templates. (See
|
templates. (See
|
||||||
`docs <https://anymail.readthedocs.io/en/latest/esps/sendgrid/#sendgrid-templates>`__.)
|
`docs <https://anymail.readthedocs.io/en/latest/esps/sendgrid/#sendgrid-templates>`__.)
|
||||||
|
* **SendGrid:** Allow merging `esp_extra["personalizations"]` dict into other message-derived
|
||||||
|
personalizations. (See
|
||||||
|
`docs <https://anymail.readthedocs.io/en/latest/esps/sendgrid/#sendgrid-esp-extra>`__.)
|
||||||
|
|
||||||
|
|
||||||
v4.0
|
v4.0
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import uuid
|
import uuid
|
||||||
|
from collections import Mapping
|
||||||
from email.utils import quote as rfc822_quote
|
from email.utils import quote as rfc822_quote
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
@@ -171,7 +172,7 @@ class SendGridPayload(RequestsPayload):
|
|||||||
pass # no merge_data for this recipient
|
pass # no merge_data for this recipient
|
||||||
self.data["personalizations"].append(personalization)
|
self.data["personalizations"].append(personalization)
|
||||||
|
|
||||||
if self.merge_field_format is None and all(field.isalnum() for field in all_fields):
|
if self.merge_field_format is None and len(all_fields) and all(field.isalnum() for field in all_fields):
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Your SendGrid merge fields don't seem to have delimiters, "
|
"Your SendGrid merge fields don't seem to have delimiters, "
|
||||||
"which can cause unexpected results with Anymail's merge_data. "
|
"which can cause unexpected results with Anymail's merge_data. "
|
||||||
@@ -347,6 +348,10 @@ class SendGridPayload(RequestsPayload):
|
|||||||
def set_esp_extra(self, extra):
|
def set_esp_extra(self, extra):
|
||||||
self.merge_field_format = extra.pop("merge_field_format", self.merge_field_format)
|
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)
|
self.use_dynamic_template = extra.pop("use_dynamic_template", self.use_dynamic_template)
|
||||||
|
if isinstance(extra.get("personalizations", None), Mapping):
|
||||||
|
# merge personalizations *dict* into other message personalizations
|
||||||
|
assert len(self.data["personalizations"]) == 1
|
||||||
|
self.data["personalizations"][0].update(extra.pop("personalizations"))
|
||||||
if "x-smtpapi" in extra:
|
if "x-smtpapi" in extra:
|
||||||
raise AnymailConfigurationError(
|
raise AnymailConfigurationError(
|
||||||
"You are attempting to use SendGrid v2 API-style x-smtpapi params "
|
"You are attempting to use SendGrid v2 API-style x-smtpapi params "
|
||||||
|
|||||||
@@ -123,6 +123,12 @@ Your :attr:`esp_extra` dict will be deeply merged into the
|
|||||||
parameters Anymail has constructed for the send, with `esp_extra`
|
parameters Anymail has constructed for the send, with `esp_extra`
|
||||||
having precedence in conflicts.
|
having precedence in conflicts.
|
||||||
|
|
||||||
|
Anymail has special handling for `esp_extra["personalizations"]`. If that value
|
||||||
|
is a `dict`, Anymail will merge that personalizations dict into the personalizations
|
||||||
|
for each message recipient. (If you pass a `list`, that will override the
|
||||||
|
personalizations Anymail normally constructs from the message, and you will need to
|
||||||
|
specify each recipient in the personalizations list yourself.)
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
@@ -140,6 +146,11 @@ Example:
|
|||||||
"substitution_tag": "%%OPEN_TRACKING_PIXEL%%",
|
"substitution_tag": "%%OPEN_TRACKING_PIXEL%%",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
# Because "personalizations" is a dict, Anymail will merge "future_feature"
|
||||||
|
# into the SendGrid personalizations array for each message recipient
|
||||||
|
"personalizations": {
|
||||||
|
"future_feature": {"future": "data"},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -627,6 +627,34 @@ class SendGridBackendAnymailFeatureTests(SendGridBackendMockAPITestCase):
|
|||||||
self.assertEqual(data['categories'], ["tag"])
|
self.assertEqual(data['categories'], ["tag"])
|
||||||
self.assertEqual(data['tracking_settings']['click_tracking'], {'enable': True})
|
self.assertEqual(data['tracking_settings']['click_tracking'], {'enable': True})
|
||||||
|
|
||||||
|
def test_esp_extra_pesonalizations(self):
|
||||||
|
self.message.to = ["First recipient <first@example.com>", "second@example.com"]
|
||||||
|
self.message.merge_data = {} # force separate messages for each 'to'
|
||||||
|
|
||||||
|
# esp_extra['personalizations'] dict merges with message-derived personalizations
|
||||||
|
self.message.esp_extra = {
|
||||||
|
"personalizations": {"future_feature": "works"}}
|
||||||
|
self.message.send()
|
||||||
|
data = self.get_api_call_json()
|
||||||
|
self.assertEqual(data['personalizations'], [
|
||||||
|
{'to': [{'email': 'first@example.com', 'name': '"First recipient"'}],
|
||||||
|
'future_feature': "works"},
|
||||||
|
{'to': [{'email': 'second@example.com'}],
|
||||||
|
'future_feature': "works"}, # merged into *every* recipient
|
||||||
|
])
|
||||||
|
|
||||||
|
# but esp_extra['personalizations'] list just overrides entire personalizations
|
||||||
|
# (for backwards compatibility)
|
||||||
|
self.message.esp_extra = {
|
||||||
|
"personalizations": [{"to": [{"email": "custom@example.com"}],
|
||||||
|
"future_feature": "works"}]}
|
||||||
|
self.message.send()
|
||||||
|
data = self.get_api_call_json()
|
||||||
|
self.assertEqual(data['personalizations'], [
|
||||||
|
{'to': [{'email': 'custom@example.com'}],
|
||||||
|
'future_feature': "works"},
|
||||||
|
])
|
||||||
|
|
||||||
# noinspection PyUnresolvedReferences
|
# noinspection PyUnresolvedReferences
|
||||||
def test_send_attaches_anymail_status(self):
|
def test_send_attaches_anymail_status(self):
|
||||||
""" The anymail_status should be attached to the message when it is sent """
|
""" The anymail_status should be attached to the message when it is sent """
|
||||||
|
|||||||
Reference in New Issue
Block a user