mirror of
https://github.com/pacnpal/django-anymail.git
synced 2025-12-20 11:51:05 -05:00
Mandrill: support esp_extra
* Merge esp_extra with Mandrill send payload * Handle pythonic forms of `recipient_metadata` and `template_content` in esp_extra * DeprecationWarning for Mandrill EmailMessage attributes inherited from Djrill
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
|
import warnings
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from ..exceptions import AnymailRequestsAPIError
|
from ..exceptions import AnymailRequestsAPIError, AnymailWarning
|
||||||
from ..message import AnymailRecipientStatus, ANYMAIL_STATUSES
|
from ..message import AnymailRecipientStatus, ANYMAIL_STATUSES
|
||||||
from ..utils import last, combine, get_anymail_setting
|
from ..utils import last, combine, get_anymail_setting
|
||||||
|
|
||||||
@@ -43,14 +44,8 @@ class MandrillBackend(AnymailRequestsBackend):
|
|||||||
return recipient_status
|
return recipient_status
|
||||||
|
|
||||||
|
|
||||||
def _expand_merge_vars(vardict):
|
class DjrillDeprecationWarning(AnymailWarning, DeprecationWarning):
|
||||||
"""Convert a Python dict to an array of name-content used by Mandrill.
|
"""Warning for features carried over from Djrill that will be removed soon"""
|
||||||
|
|
||||||
{ name: value, ... } --> [ {'name': name, 'content': value }, ... ]
|
|
||||||
"""
|
|
||||||
# For testing reproducibility, we sort the keys
|
|
||||||
return [{'name': name, 'content': vardict[name]}
|
|
||||||
for name in sorted(vardict.keys())]
|
|
||||||
|
|
||||||
|
|
||||||
def encode_date_for_mandrill(dt):
|
def encode_date_for_mandrill(dt):
|
||||||
@@ -69,6 +64,10 @@ def encode_date_for_mandrill(dt):
|
|||||||
|
|
||||||
class MandrillPayload(RequestsPayload):
|
class MandrillPayload(RequestsPayload):
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.esp_extra = {} # late-bound in serialize_data
|
||||||
|
super(MandrillPayload, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
def get_api_endpoint(self):
|
def get_api_endpoint(self):
|
||||||
if 'template_name' in self.data:
|
if 'template_name' in self.data:
|
||||||
return "messages/send-template.json"
|
return "messages/send-template.json"
|
||||||
@@ -76,6 +75,7 @@ class MandrillPayload(RequestsPayload):
|
|||||||
return "messages/send.json"
|
return "messages/send.json"
|
||||||
|
|
||||||
def serialize_data(self):
|
def serialize_data(self):
|
||||||
|
self.process_esp_extra()
|
||||||
return self.serialize_json(self.data)
|
return self.serialize_json(self.data)
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -89,7 +89,9 @@ class MandrillPayload(RequestsPayload):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def set_from_email(self, email):
|
def set_from_email(self, email):
|
||||||
if not getattr(self.message, "use_template_from", False): # Djrill compat!
|
if getattr(self.message, "use_template_from", False):
|
||||||
|
self.deprecation_warning('message.use_template_from', 'message.from_email = None')
|
||||||
|
else:
|
||||||
self.data["message"]["from_email"] = email.email
|
self.data["message"]["from_email"] = email.email
|
||||||
if email.name:
|
if email.name:
|
||||||
self.data["message"]["from_name"] = email.name
|
self.data["message"]["from_name"] = email.name
|
||||||
@@ -100,7 +102,9 @@ class MandrillPayload(RequestsPayload):
|
|||||||
to_list.append({"email": email.email, "name": email.name, "type": recipient_type})
|
to_list.append({"email": email.email, "name": email.name, "type": recipient_type})
|
||||||
|
|
||||||
def set_subject(self, subject):
|
def set_subject(self, subject):
|
||||||
if not getattr(self.message, "use_template_subject", False): # Djrill compat!
|
if getattr(self.message, "use_template_subject", False):
|
||||||
|
self.deprecation_warning('message.use_template_subject', 'message.subject = None')
|
||||||
|
else:
|
||||||
self.data["message"]["subject"] = subject
|
self.data["message"]["subject"] = subject
|
||||||
|
|
||||||
def set_reply_to(self, emails):
|
def set_reply_to(self, emails):
|
||||||
@@ -166,9 +170,59 @@ class MandrillPayload(RequestsPayload):
|
|||||||
]
|
]
|
||||||
|
|
||||||
def set_esp_extra(self, extra):
|
def set_esp_extra(self, extra):
|
||||||
|
# late bind in serialize_data, so that obsolete Djrill attrs can contribute
|
||||||
|
self.esp_extra = extra
|
||||||
|
|
||||||
|
def process_esp_extra(self):
|
||||||
|
if self.esp_extra is not None and len(self.esp_extra) > 0:
|
||||||
|
esp_extra = self.esp_extra
|
||||||
|
# Convert pythonic template_content dict to Mandrill name/content list
|
||||||
|
try:
|
||||||
|
template_content = esp_extra['template_content']
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
if hasattr(template_content, 'items'): # if it's dict-like
|
||||||
|
if esp_extra is self.esp_extra:
|
||||||
|
esp_extra = self.esp_extra.copy() # don't modify caller's value
|
||||||
|
esp_extra['template_content'] = [
|
||||||
|
{'name': var, 'content': value}
|
||||||
|
for var, value in template_content.items()]
|
||||||
|
# Convert pythonic recipient_metadata dict to Mandrill rcpt/values list
|
||||||
|
try:
|
||||||
|
recipient_metadata = esp_extra['message']['recipient_metadata']
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
if hasattr(recipient_metadata, 'keys'): # if it's dict-like
|
||||||
|
if esp_extra['message'] is self.esp_extra['message']:
|
||||||
|
esp_extra['message'] = self.esp_extra['message'].copy() # don't modify caller's value
|
||||||
|
# For testing reproducibility, we sort the recipients
|
||||||
|
esp_extra['message']['recipient_metadata'] = [
|
||||||
|
{'rcpt': rcpt, 'values': recipient_metadata[rcpt]}
|
||||||
|
for rcpt in sorted(recipient_metadata.keys())]
|
||||||
|
# Merge esp_extra with payload data: shallow merge within ['message'] and top-level keys
|
||||||
|
self.data.update({k:v for k,v in esp_extra.items() if k != 'message'})
|
||||||
|
try:
|
||||||
|
self.data['message'].update(esp_extra['message'])
|
||||||
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Djrill leftovers
|
# Djrill deprecated message attrs
|
||||||
|
|
||||||
|
def deprecation_warning(self, feature, replacement=None):
|
||||||
|
msg = "Djrill's `%s` will be removed in an upcoming Anymail release." % feature
|
||||||
|
if replacement:
|
||||||
|
msg += " Use `%s` instead." % replacement
|
||||||
|
warnings.warn(msg, DjrillDeprecationWarning)
|
||||||
|
|
||||||
|
def deprecated_to_esp_extra(self, attr, in_message_dict=False):
|
||||||
|
feature = "message.%s" % attr
|
||||||
|
if in_message_dict:
|
||||||
|
replacement = "message.esp_extra = {'message': {'%s': <value>}}" % attr
|
||||||
|
else:
|
||||||
|
replacement = "message.esp_extra = {'%s': <value>}" % attr
|
||||||
|
self.deprecation_warning(feature, replacement)
|
||||||
|
|
||||||
esp_message_attrs = (
|
esp_message_attrs = (
|
||||||
('async', last, None),
|
('async', last, None),
|
||||||
@@ -188,25 +242,40 @@ class MandrillPayload(RequestsPayload):
|
|||||||
('subaccount', last, None),
|
('subaccount', last, None),
|
||||||
('google_analytics_domains', last, None),
|
('google_analytics_domains', last, None),
|
||||||
('google_analytics_campaign', last, None),
|
('google_analytics_campaign', last, None),
|
||||||
|
('global_merge_vars', combine, None),
|
||||||
|
('merge_vars', combine, None),
|
||||||
('recipient_metadata', combine, None),
|
('recipient_metadata', combine, None),
|
||||||
('template_content', combine, _expand_merge_vars),
|
('template_name', last, None),
|
||||||
|
('template_content', combine, None),
|
||||||
)
|
)
|
||||||
|
|
||||||
def set_async(self, async):
|
def set_async(self, async):
|
||||||
self.data["async"] = async
|
self.deprecated_to_esp_extra('async')
|
||||||
|
self.esp_extra['async'] = async
|
||||||
|
|
||||||
def set_ip_pool(self, ip_pool):
|
def set_ip_pool(self, ip_pool):
|
||||||
self.data["ip_pool"] = ip_pool
|
self.deprecated_to_esp_extra('ip_pool')
|
||||||
|
self.esp_extra['ip_pool'] = ip_pool
|
||||||
|
|
||||||
|
def set_global_merge_vars(self, global_merge_vars):
|
||||||
|
self.deprecation_warning('message.global_merge_vars', 'message.merge_global_data')
|
||||||
|
self.set_merge_global_data(global_merge_vars)
|
||||||
|
|
||||||
|
def set_merge_vars(self, merge_vars):
|
||||||
|
self.deprecation_warning('message.merge_vars', 'message.merge_data')
|
||||||
|
self.set_merge_data(merge_vars)
|
||||||
|
|
||||||
|
def set_template_name(self, template_name):
|
||||||
|
self.deprecation_warning('message.template_name', 'message.template_id')
|
||||||
|
self.set_template_id(template_name)
|
||||||
|
|
||||||
def set_template_content(self, template_content):
|
def set_template_content(self, template_content):
|
||||||
self.data["template_content"] = template_content
|
self.deprecated_to_esp_extra('template_content')
|
||||||
|
self.esp_extra['template_content'] = template_content
|
||||||
|
|
||||||
def set_recipient_metadata(self, recipient_metadata):
|
def set_recipient_metadata(self, recipient_metadata):
|
||||||
# For testing reproducibility, we sort the recipients
|
self.deprecated_to_esp_extra('recipient_metadata', in_message_dict=True)
|
||||||
self.data['message']['recipient_metadata'] = [
|
self.esp_extra.setdefault('message', {})['recipient_metadata'] = recipient_metadata
|
||||||
{'rcpt': rcpt, 'values': recipient_metadata[rcpt]}
|
|
||||||
for rcpt in sorted(recipient_metadata.keys())
|
|
||||||
]
|
|
||||||
|
|
||||||
# Set up simple set_<attr> functions for any missing esp_message_attrs attrs
|
# Set up simple set_<attr> functions for any missing esp_message_attrs attrs
|
||||||
# (avoids dozens of simple `self.data["message"][<attr>] = value` functions)
|
# (avoids dozens of simple `self.data["message"][<attr>] = value` functions)
|
||||||
@@ -225,7 +294,8 @@ class MandrillPayload(RequestsPayload):
|
|||||||
def make_setter(attr, setter_name):
|
def make_setter(attr, setter_name):
|
||||||
# sure wish we could use functools.partial to create instance methods (descriptors)
|
# sure wish we could use functools.partial to create instance methods (descriptors)
|
||||||
def setter(self, value):
|
def setter(self, value):
|
||||||
self.data["message"][attr] = value
|
self.deprecated_to_esp_extra(attr, in_message_dict=True)
|
||||||
|
self.esp_extra.setdefault('message', {})[attr] = value
|
||||||
setter.__name__ = setter_name
|
setter.__name__ = setter_name
|
||||||
return setter
|
return setter
|
||||||
|
|
||||||
|
|||||||
@@ -97,9 +97,38 @@ which is the secure, production version of Mandrill's 1.0 API.
|
|||||||
esp_extra support
|
esp_extra support
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
Anymail's Mandrill backend does not yet implement the
|
To use Mandrill features not directly supported by Anymail, you can
|
||||||
:attr:`~anymail.message.AnymailMessage.esp_extra` feature.
|
set a message's :attr:`~anymail.message.AnymailMessage.esp_extra` to
|
||||||
|
a `dict` of parameters to merge into Mandrill's `messages/send API`_ call.
|
||||||
|
Note that a few parameters go at the top level, but Mandrill expects
|
||||||
|
most options within a `'message'` sub-dict---be sure to check their
|
||||||
|
API docs:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
message.esp_extra = {
|
||||||
|
# Mandrill expects 'ip_pool' at top level...
|
||||||
|
'ip_pool': 'Bulk Pool',
|
||||||
|
# ... but 'subaccount' must be within a 'message' dict:
|
||||||
|
'message': {
|
||||||
|
'subaccount': 'Marketing Dept.'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Anymail has special handling that lets you specify Mandrill's
|
||||||
|
`'recipient_metadata'` as a simple, pythonic `dict` (similar in form
|
||||||
|
to Anymail's :attr:`~anymail.message.AnymailMessage.merge_data`),
|
||||||
|
rather than Mandrill's more complex list of rcpt/values dicts.
|
||||||
|
You can use whichever style you prefer (but either way,
|
||||||
|
recipient_metadata must be in `esp_extra['message']`).
|
||||||
|
|
||||||
|
Similary, Anymail allows Mandrill's `'template_content'` in esp_extra
|
||||||
|
(top level) either as a pythonic `dict` (similar to Anymail's
|
||||||
|
:attr:`~anymail.message.AnymailMessage.merge_global_data`) or
|
||||||
|
as Mandrill's more complex list of name/content dicts.
|
||||||
|
|
||||||
|
.. _messages/send API:
|
||||||
|
https://mandrillapp.com/api/docs/messages.JSON.html#method=send
|
||||||
|
|
||||||
.. _mandrill-templates:
|
.. _mandrill-templates:
|
||||||
|
|
||||||
@@ -222,16 +251,21 @@ Changes to settings
|
|||||||
the values from :setting:`ANYMAIL_SEND_DEFAULTS`.
|
the values from :setting:`ANYMAIL_SEND_DEFAULTS`.
|
||||||
|
|
||||||
``MANDRILL_SUBACCOUNT``
|
``MANDRILL_SUBACCOUNT``
|
||||||
Use :setting:`ANYMAIL_MANDRILL_SEND_DEFAULTS`:
|
Set :ref:`esp_extra <mandrill-esp-extra>`
|
||||||
|
globally in :setting:`ANYMAIL_SEND_DEFAULTS`:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
ANYMAIL = {
|
ANYMAIL = {
|
||||||
...
|
...
|
||||||
"MANDRILL_SEND_DEFAULTS": {
|
"MANDRILL_SEND_DEFAULTS": {
|
||||||
|
"esp_extra": {
|
||||||
|
"message": {
|
||||||
"subaccount": "<your subaccount>"
|
"subaccount": "<your subaccount>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
``MANDRILL_IGNORE_RECIPIENT_STATUS``
|
``MANDRILL_IGNORE_RECIPIENT_STATUS``
|
||||||
Renamed to :setting:`ANYMAIL_IGNORE_RECIPIENT_STATUS`
|
Renamed to :setting:`ANYMAIL_IGNORE_RECIPIENT_STATUS`
|
||||||
@@ -290,13 +324,30 @@ Changes to EmailMessage attributes
|
|||||||
to use the values from the stored template.
|
to use the values from the stored template.
|
||||||
|
|
||||||
**Other Mandrill-specific attributes**
|
**Other Mandrill-specific attributes**
|
||||||
Are currently still supported by Anymail's Mandrill backend,
|
Djrill allowed nearly all Mandrill API parameters to be set
|
||||||
but will be ignored by other Anymail backends.
|
as attributes directly on an EmailMessage. With Anymail, you
|
||||||
|
should instead set these in the message's
|
||||||
|
:ref:`esp_extra <mandrill-esp-extra>` dict as described above.
|
||||||
|
|
||||||
|
Although the Djrill style attributes are still supported (for now),
|
||||||
|
Anymail will issue a :exc:`DeprecationWarning` if you try to use them.
|
||||||
|
These warnings are visible during tests (with Django's default test
|
||||||
|
runner), and will explain how to update your code.
|
||||||
|
|
||||||
|
You can also use the following git grep expression to find potential
|
||||||
|
problems:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
git grep -w \
|
||||||
|
-e 'async' -e 'auto_html' -e 'auto_text' -e 'from_name' -e 'global_merge_vars' \
|
||||||
|
-e 'google_analytics_campaign' -e 'google_analytics_domains' -e 'important' \
|
||||||
|
-e 'inline_css' -e 'ip_pool' -e 'merge_language' -e 'merge_vars' \
|
||||||
|
-e 'preserve_recipients' -e 'recipient_metadata' -e 'return_path_domain' \
|
||||||
|
-e 'signing_domain' -e 'subaccount' -e 'template_content' -e 'template_name' \
|
||||||
|
-e 'tracking_domain' -e 'url_strip_qs' -e 'use_template_from' -e 'use_template_subject' \
|
||||||
|
-e 'view_content_link'
|
||||||
|
|
||||||
It's best to eliminate them if they're not essential
|
|
||||||
to your code. In the future, the Mandrill-only attributes
|
|
||||||
will be moved into the
|
|
||||||
:attr:`~anymail.message.AnymailMessage.esp_extra` dict.
|
|
||||||
|
|
||||||
**Inline images**
|
**Inline images**
|
||||||
Djrill (incorrectly) used the presence of a :mailheader:`Content-ID`
|
Djrill (incorrectly) used the presence of a :mailheader:`Content-ID`
|
||||||
|
|||||||
@@ -401,6 +401,69 @@ class MandrillBackendAnymailFeatureTests(MandrillBackendMockAPITestCase):
|
|||||||
data = self.get_api_call_json()
|
data = self.get_api_call_json()
|
||||||
self.assertNotIn('subject', data['message'])
|
self.assertNotIn('subject', data['message'])
|
||||||
|
|
||||||
|
def test_esp_extra(self):
|
||||||
|
self.message.esp_extra = {
|
||||||
|
'ip_pool': 'Bulk Pool', # Mandrill send param that goes at top level of API payload
|
||||||
|
'message': {
|
||||||
|
'subaccount': 'Marketing Dept.' # param that goes within message dict
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.message.tags = ['test-tag'] # make sure non-esp_extra params are merged
|
||||||
|
self.message.send()
|
||||||
|
data = self.get_api_call_json()
|
||||||
|
self.assertEqual(data['ip_pool'], 'Bulk Pool')
|
||||||
|
self.assertEqual(data['message']['subaccount'], 'Marketing Dept.')
|
||||||
|
self.assertEqual(data['message']['tags'], ['test-tag'])
|
||||||
|
|
||||||
|
def test_esp_extra_recipient_metadata(self):
|
||||||
|
"""Anymail allows pythonic recipient_metadata dict"""
|
||||||
|
self.message.esp_extra = {'message': {'recipient_metadata': {
|
||||||
|
# Anymail expands simple python dicts into the more-verbose
|
||||||
|
# rcpt/values lists the Mandrill API uses
|
||||||
|
"customer@example.com": {'cust_id': "67890", 'order_id': "54321"},
|
||||||
|
"guest@example.com": {'cust_id': "94107", 'order_id': "43215"} ,
|
||||||
|
}}}
|
||||||
|
self.message.send()
|
||||||
|
data = self.get_api_call_json()
|
||||||
|
self.assertCountEqual(data['message']['recipient_metadata'], [
|
||||||
|
{'rcpt': "customer@example.com", 'values': {'cust_id': "67890", 'order_id': "54321"}},
|
||||||
|
{'rcpt': "guest@example.com", 'values': {'cust_id': "94107", 'order_id': "43215"}}])
|
||||||
|
|
||||||
|
# You can also just supply it in Mandrill's native form
|
||||||
|
self.message.esp_extra = {'message': {'recipient_metadata': [
|
||||||
|
{'rcpt': "customer@example.com", 'values': {'cust_id': "80806", 'order_id': "70701"}},
|
||||||
|
{'rcpt': "guest@example.com", 'values': {'cust_id': "21212", 'order_id': "10305"}}]}}
|
||||||
|
self.message.send()
|
||||||
|
data = self.get_api_call_json()
|
||||||
|
self.assertCountEqual(data['message']['recipient_metadata'], [
|
||||||
|
{'rcpt': "customer@example.com", 'values': {'cust_id': "80806", 'order_id': "70701"}},
|
||||||
|
{'rcpt': "guest@example.com", 'values': {'cust_id': "21212", 'order_id': "10305"}}])
|
||||||
|
|
||||||
|
def test_esp_extra_template_content(self):
|
||||||
|
"""Anymail allows pythonic template_content dict"""
|
||||||
|
self.message.template_id = "welcome_template" # forces send-template API and default template_content
|
||||||
|
self.message.esp_extra = {'template_content': {
|
||||||
|
# Anymail expands simple python dicts into the more-verbose name/content
|
||||||
|
# structures the Mandrill API uses
|
||||||
|
'HEADLINE': "<h1>Specials Just For *|FNAME|*</h1>",
|
||||||
|
'OFFER_BLOCK': "<p><em>Half off</em> all fruit</p>",
|
||||||
|
}}
|
||||||
|
self.message.send()
|
||||||
|
data = self.get_api_call_json()
|
||||||
|
self.assertCountEqual(data['template_content'], [
|
||||||
|
{'name': "HEADLINE", 'content': "<h1>Specials Just For *|FNAME|*</h1>"},
|
||||||
|
{'name': "OFFER_BLOCK", 'content': "<p><em>Half off</em> all fruit</p>"}])
|
||||||
|
|
||||||
|
# You can also just supply it in Mandrill's native form
|
||||||
|
self.message.esp_extra = {'template_content': [
|
||||||
|
{'name': "HEADLINE", 'content': "<h1>Exciting offers for *|FNAME|*</h1>"},
|
||||||
|
{'name': "OFFER_BLOCK", 'content': "<p><em>25% off</em> all fruit</p>"}]}
|
||||||
|
self.message.send()
|
||||||
|
data = self.get_api_call_json()
|
||||||
|
self.assertCountEqual(data['template_content'], [
|
||||||
|
{'name': "HEADLINE", 'content': "<h1>Exciting offers for *|FNAME|*</h1>"},
|
||||||
|
{'name': "OFFER_BLOCK", 'content': "<p><em>25% off</em> all fruit</p>"}])
|
||||||
|
|
||||||
def test_default_omits_options(self):
|
def test_default_omits_options(self):
|
||||||
"""Make sure by default we don't send any ESP-specific options.
|
"""Make sure by default we don't send any ESP-specific options.
|
||||||
|
|
||||||
@@ -411,11 +474,15 @@ class MandrillBackendAnymailFeatureTests(MandrillBackendMockAPITestCase):
|
|||||||
self.message.send()
|
self.message.send()
|
||||||
self.assert_esp_called("/messages/send.json")
|
self.assert_esp_called("/messages/send.json")
|
||||||
data = self.get_api_call_json()
|
data = self.get_api_call_json()
|
||||||
|
self.assertNotIn('global_merge_vars', data['message'])
|
||||||
|
self.assertNotIn('merge_vars', data['message'])
|
||||||
self.assertNotIn('metadata', data['message'])
|
self.assertNotIn('metadata', data['message'])
|
||||||
self.assertNotIn('send_at', data)
|
self.assertNotIn('send_at', data)
|
||||||
self.assertNotIn('tags', data['message'])
|
self.assertNotIn('tags', data['message'])
|
||||||
self.assertNotIn('track_opens', data['message'])
|
self.assertNotIn('template_content', data['message'])
|
||||||
|
self.assertNotIn('template_name', data['message'])
|
||||||
self.assertNotIn('track_clicks', data['message'])
|
self.assertNotIn('track_clicks', data['message'])
|
||||||
|
self.assertNotIn('track_opens', data['message'])
|
||||||
|
|
||||||
# noinspection PyUnresolvedReferences
|
# noinspection PyUnresolvedReferences
|
||||||
def test_send_attaches_anymail_status(self):
|
def test_send_attaches_anymail_status(self):
|
||||||
|
|||||||
@@ -2,54 +2,85 @@ from datetime import date
|
|||||||
from django.core import mail
|
from django.core import mail
|
||||||
from django.test import override_settings
|
from django.test import override_settings
|
||||||
|
|
||||||
from anymail.exceptions import AnymailAPIError, AnymailSerializationError
|
from anymail.exceptions import AnymailSerializationError
|
||||||
|
|
||||||
from .test_mandrill_backend import MandrillBackendMockAPITestCase
|
from .test_mandrill_backend import MandrillBackendMockAPITestCase
|
||||||
|
|
||||||
|
|
||||||
class MandrillBackendDjrillFeatureTests(MandrillBackendMockAPITestCase):
|
class MandrillBackendDjrillFeatureTests(MandrillBackendMockAPITestCase):
|
||||||
"""Test backend support for features leftover from Djrill"""
|
"""Test backend support for deprecated features leftover from Djrill"""
|
||||||
|
|
||||||
# Most of these features should be moved to esp_extra.
|
# These features should now be accessed through esp_extra
|
||||||
# The template and merge_ta
|
|
||||||
|
|
||||||
def test_djrill_message_options(self):
|
def test_async(self):
|
||||||
self.message.url_strip_qs = True
|
|
||||||
self.message.important = True
|
|
||||||
self.message.auto_text = True
|
|
||||||
self.message.auto_html = True
|
|
||||||
self.message.inline_css = True
|
|
||||||
self.message.preserve_recipients = True
|
|
||||||
self.message.view_content_link = False
|
|
||||||
self.message.tracking_domain = "click.example.com"
|
|
||||||
self.message.signing_domain = "example.com"
|
|
||||||
self.message.return_path_domain = "support.example.com"
|
|
||||||
self.message.subaccount = "marketing-dept"
|
|
||||||
self.message.async = True
|
self.message.async = True
|
||||||
self.message.ip_pool = "Bulk Pool"
|
with self.assertWarnsRegex(DeprecationWarning, 'async'):
|
||||||
self.message.send()
|
self.message.send()
|
||||||
data = self.get_api_call_json()
|
data = self.get_api_call_json()
|
||||||
self.assertEqual(data['message']['url_strip_qs'], True)
|
|
||||||
self.assertEqual(data['message']['important'], True)
|
|
||||||
self.assertEqual(data['message']['auto_text'], True)
|
|
||||||
self.assertEqual(data['message']['auto_html'], True)
|
|
||||||
self.assertEqual(data['message']['inline_css'], True)
|
|
||||||
self.assertEqual(data['message']['preserve_recipients'], True)
|
|
||||||
self.assertEqual(data['message']['view_content_link'], False)
|
|
||||||
self.assertEqual(data['message']['tracking_domain'], "click.example.com")
|
|
||||||
self.assertEqual(data['message']['signing_domain'], "example.com")
|
|
||||||
self.assertEqual(data['message']['return_path_domain'], "support.example.com")
|
|
||||||
self.assertEqual(data['message']['subaccount'], "marketing-dept")
|
|
||||||
self.assertEqual(data['async'], True)
|
self.assertEqual(data['async'], True)
|
||||||
self.assertEqual(data['ip_pool'], "Bulk Pool")
|
|
||||||
|
|
||||||
def test_google_analytics(self):
|
def test_auto_html(self):
|
||||||
self.message.google_analytics_domains = ["example.com"]
|
self.message.auto_html = True
|
||||||
|
with self.assertWarnsRegex(DeprecationWarning, 'auto_html'):
|
||||||
|
self.message.send()
|
||||||
|
data = self.get_api_call_json()
|
||||||
|
self.assertEqual(data['message']['auto_html'], True)
|
||||||
|
|
||||||
|
def test_auto_text(self):
|
||||||
|
self.message.auto_text = True
|
||||||
|
with self.assertWarnsRegex(DeprecationWarning, 'auto_text'):
|
||||||
|
self.message.send()
|
||||||
|
data = self.get_api_call_json()
|
||||||
|
self.assertEqual(data['message']['auto_text'], True)
|
||||||
|
|
||||||
|
def test_google_analytics_campaign(self):
|
||||||
self.message.google_analytics_campaign = "Email Receipts"
|
self.message.google_analytics_campaign = "Email Receipts"
|
||||||
|
with self.assertWarnsRegex(DeprecationWarning, 'google_analytics_campaign'):
|
||||||
|
self.message.send()
|
||||||
|
data = self.get_api_call_json()
|
||||||
|
self.assertEqual(data['message']['google_analytics_campaign'], "Email Receipts")
|
||||||
|
|
||||||
|
def test_google_analytics_domains(self):
|
||||||
|
self.message.google_analytics_domains = ["example.com"]
|
||||||
|
with self.assertWarnsRegex(DeprecationWarning, 'google_analytics_domains'):
|
||||||
self.message.send()
|
self.message.send()
|
||||||
data = self.get_api_call_json()
|
data = self.get_api_call_json()
|
||||||
self.assertEqual(data['message']['google_analytics_domains'], ["example.com"])
|
self.assertEqual(data['message']['google_analytics_domains'], ["example.com"])
|
||||||
self.assertEqual(data['message']['google_analytics_campaign'], "Email Receipts")
|
|
||||||
|
def test_important(self):
|
||||||
|
self.message.important = True
|
||||||
|
with self.assertWarnsRegex(DeprecationWarning, 'important'):
|
||||||
|
self.message.send()
|
||||||
|
data = self.get_api_call_json()
|
||||||
|
self.assertEqual(data['message']['important'], True)
|
||||||
|
|
||||||
|
def test_inline_css(self):
|
||||||
|
self.message.inline_css = True
|
||||||
|
with self.assertWarnsRegex(DeprecationWarning, 'inline_css'):
|
||||||
|
self.message.send()
|
||||||
|
data = self.get_api_call_json()
|
||||||
|
self.assertEqual(data['message']['inline_css'], True)
|
||||||
|
|
||||||
|
def test_ip_pool(self):
|
||||||
|
self.message.ip_pool = "Bulk Pool"
|
||||||
|
with self.assertWarnsRegex(DeprecationWarning, 'ip_pool'):
|
||||||
|
self.message.send()
|
||||||
|
data = self.get_api_call_json()
|
||||||
|
self.assertEqual(data['ip_pool'], "Bulk Pool")
|
||||||
|
|
||||||
|
def test_merge_language(self):
|
||||||
|
self.message.merge_language = "mailchimp"
|
||||||
|
with self.assertWarnsRegex(DeprecationWarning, 'merge_language'):
|
||||||
|
self.message.send()
|
||||||
|
data = self.get_api_call_json()
|
||||||
|
self.assertEqual(data['message']['merge_language'], "mailchimp")
|
||||||
|
|
||||||
|
def test_preserve_recipients(self):
|
||||||
|
self.message.preserve_recipients = True
|
||||||
|
with self.assertWarnsRegex(DeprecationWarning, 'preserve_recipients'):
|
||||||
|
self.message.send()
|
||||||
|
data = self.get_api_call_json()
|
||||||
|
self.assertEqual(data['message']['preserve_recipients'], True)
|
||||||
|
|
||||||
def test_recipient_metadata(self):
|
def test_recipient_metadata(self):
|
||||||
self.message.recipient_metadata = {
|
self.message.recipient_metadata = {
|
||||||
@@ -58,33 +89,87 @@ class MandrillBackendDjrillFeatureTests(MandrillBackendMockAPITestCase):
|
|||||||
"customer@example.com": {'cust_id': "67890", 'order_id': "54321"},
|
"customer@example.com": {'cust_id': "67890", 'order_id': "54321"},
|
||||||
"guest@example.com": {'cust_id': "94107", 'order_id': "43215"}
|
"guest@example.com": {'cust_id': "94107", 'order_id': "43215"}
|
||||||
}
|
}
|
||||||
|
with self.assertWarnsRegex(DeprecationWarning, 'recipient_metadata'):
|
||||||
self.message.send()
|
self.message.send()
|
||||||
data = self.get_api_call_json()
|
data = self.get_api_call_json()
|
||||||
self.assertEqual(data['message']['recipient_metadata'],
|
self.assertCountEqual(data['message']['recipient_metadata'], [
|
||||||
[{'rcpt': "customer@example.com",
|
{'rcpt': "customer@example.com",
|
||||||
'values': {'cust_id': "67890", 'order_id': "54321"}},
|
'values': {'cust_id': "67890", 'order_id': "54321"}},
|
||||||
{'rcpt': "guest@example.com",
|
{'rcpt': "guest@example.com",
|
||||||
'values': {'cust_id': "94107", 'order_id': "43215"}}
|
'values': {'cust_id': "94107", 'order_id': "43215"}}])
|
||||||
])
|
|
||||||
|
|
||||||
def test_no_subaccount_by_default(self):
|
def test_return_path_domain(self):
|
||||||
mail.send_mail('Subject', 'Body', 'from@example.com', ['to@example.com'])
|
self.message.return_path_domain = "support.example.com"
|
||||||
|
with self.assertWarnsRegex(DeprecationWarning, 'return_path_domain'):
|
||||||
|
self.message.send()
|
||||||
data = self.get_api_call_json()
|
data = self.get_api_call_json()
|
||||||
self.assertFalse('subaccount' in data['message'])
|
self.assertEqual(data['message']['return_path_domain'], "support.example.com")
|
||||||
|
|
||||||
@override_settings(ANYMAIL_MANDRILL_SEND_DEFAULTS={'subaccount': 'test_subaccount'})
|
def test_signing_domain(self):
|
||||||
def test_subaccount_setting(self):
|
self.message.signing_domain = "example.com"
|
||||||
mail.send_mail('Subject', 'Body', 'from@example.com', ['to@example.com'])
|
with self.assertWarnsRegex(DeprecationWarning, 'signing_domain'):
|
||||||
|
self.message.send()
|
||||||
data = self.get_api_call_json()
|
data = self.get_api_call_json()
|
||||||
self.assertEqual(data['message']['subaccount'], "test_subaccount")
|
self.assertEqual(data['message']['signing_domain'], "example.com")
|
||||||
|
|
||||||
@override_settings(ANYMAIL_MANDRILL_SEND_DEFAULTS={'subaccount': 'global_setting_subaccount'})
|
def test_subaccount(self):
|
||||||
def test_subaccount_message_overrides_setting(self):
|
self.message.subaccount = "marketing-dept"
|
||||||
message = mail.EmailMessage('Subject', 'Body', 'from@example.com', ['to@example.com'])
|
with self.assertWarnsRegex(DeprecationWarning, 'subaccount'):
|
||||||
message.subaccount = "individual_message_subaccount" # should override global setting
|
self.message.send()
|
||||||
message.send()
|
|
||||||
data = self.get_api_call_json()
|
data = self.get_api_call_json()
|
||||||
self.assertEqual(data['message']['subaccount'], "individual_message_subaccount")
|
self.assertEqual(data['message']['subaccount'], "marketing-dept")
|
||||||
|
|
||||||
|
def test_template_content(self):
|
||||||
|
self.message.template_content = {
|
||||||
|
'HEADLINE': "<h1>Specials Just For *|FNAME|*</h1>",
|
||||||
|
'OFFER_BLOCK': "<p><em>Half off</em> all fruit</p>"
|
||||||
|
}
|
||||||
|
with self.assertWarnsRegex(DeprecationWarning, 'template_content'):
|
||||||
|
self.message.send()
|
||||||
|
data = self.get_api_call_json()
|
||||||
|
# Anymail expands simple python dicts into the more-verbose name/content
|
||||||
|
# structures the Mandrill API uses
|
||||||
|
self.assertCountEqual(data['template_content'], [
|
||||||
|
{'name': "HEADLINE", 'content': "<h1>Specials Just For *|FNAME|*</h1>"},
|
||||||
|
{'name': "OFFER_BLOCK", 'content': "<p><em>Half off</em> all fruit</p>"}])
|
||||||
|
|
||||||
|
def test_tracking_domain(self):
|
||||||
|
self.message.tracking_domain = "click.example.com"
|
||||||
|
with self.assertWarnsRegex(DeprecationWarning, 'tracking_domain'):
|
||||||
|
self.message.send()
|
||||||
|
data = self.get_api_call_json()
|
||||||
|
self.assertEqual(data['message']['tracking_domain'], "click.example.com")
|
||||||
|
|
||||||
|
def test_url_strip_qs(self):
|
||||||
|
self.message.url_strip_qs = True
|
||||||
|
with self.assertWarnsRegex(DeprecationWarning, 'url_strip_qs'):
|
||||||
|
self.message.send()
|
||||||
|
data = self.get_api_call_json()
|
||||||
|
self.assertEqual(data['message']['url_strip_qs'], True)
|
||||||
|
|
||||||
|
def test_use_template_from(self):
|
||||||
|
self.message.template_id = "PERSONALIZED_SPECIALS" # forces send-template api
|
||||||
|
self.message.use_template_from = True
|
||||||
|
with self.assertWarnsRegex(DeprecationWarning, 'use_template_from'):
|
||||||
|
self.message.send()
|
||||||
|
data = self.get_api_call_json()
|
||||||
|
self.assertNotIn('from_email', data['message'])
|
||||||
|
self.assertNotIn('from_name', data['message'])
|
||||||
|
|
||||||
|
def test_use_template_subject(self):
|
||||||
|
self.message.template_id = "PERSONALIZED_SPECIALS" # force send-template API
|
||||||
|
self.message.use_template_subject = True
|
||||||
|
with self.assertWarnsRegex(DeprecationWarning, 'use_template_subject'):
|
||||||
|
self.message.send()
|
||||||
|
data = self.get_api_call_json()
|
||||||
|
self.assertNotIn('subject', data['message'])
|
||||||
|
|
||||||
|
def test_view_content_link(self):
|
||||||
|
self.message.view_content_link = True
|
||||||
|
with self.assertWarnsRegex(DeprecationWarning, 'view_content_link'):
|
||||||
|
self.message.send()
|
||||||
|
data = self.get_api_call_json()
|
||||||
|
self.assertEqual(data['message']['view_content_link'], True)
|
||||||
|
|
||||||
def test_default_omits_options(self):
|
def test_default_omits_options(self):
|
||||||
"""Make sure by default we don't send any Mandrill-specific options.
|
"""Make sure by default we don't send any Mandrill-specific options.
|
||||||
@@ -96,25 +181,25 @@ class MandrillBackendDjrillFeatureTests(MandrillBackendMockAPITestCase):
|
|||||||
self.message.send()
|
self.message.send()
|
||||||
self.assert_esp_called("/messages/send.json")
|
self.assert_esp_called("/messages/send.json")
|
||||||
data = self.get_api_call_json()
|
data = self.get_api_call_json()
|
||||||
self.assertFalse('from_name' in data['message'])
|
|
||||||
self.assertFalse('bcc_address' in data['message'])
|
|
||||||
self.assertFalse('important' in data['message'])
|
|
||||||
self.assertFalse('auto_text' in data['message'])
|
|
||||||
self.assertFalse('auto_html' in data['message'])
|
self.assertFalse('auto_html' in data['message'])
|
||||||
self.assertFalse('inline_css' in data['message'])
|
self.assertFalse('auto_text' in data['message'])
|
||||||
self.assertFalse('url_strip_qs' in data['message'])
|
self.assertFalse('bcc_address' in data['message'])
|
||||||
self.assertFalse('preserve_recipients' in data['message'])
|
self.assertFalse('from_name' in data['message'])
|
||||||
self.assertFalse('view_content_link' in data['message'])
|
|
||||||
self.assertFalse('tracking_domain' in data['message'])
|
|
||||||
self.assertFalse('signing_domain' in data['message'])
|
|
||||||
self.assertFalse('return_path_domain' in data['message'])
|
|
||||||
self.assertFalse('subaccount' in data['message'])
|
|
||||||
self.assertFalse('google_analytics_domains' in data['message'])
|
|
||||||
self.assertFalse('google_analytics_campaign' in data['message'])
|
|
||||||
self.assertFalse('merge_language' in data['message'])
|
|
||||||
self.assertFalse('global_merge_vars' in data['message'])
|
self.assertFalse('global_merge_vars' in data['message'])
|
||||||
|
self.assertFalse('google_analytics_campaign' in data['message'])
|
||||||
|
self.assertFalse('google_analytics_domains' in data['message'])
|
||||||
|
self.assertFalse('important' in data['message'])
|
||||||
|
self.assertFalse('inline_css' in data['message'])
|
||||||
|
self.assertFalse('merge_language' in data['message'])
|
||||||
self.assertFalse('merge_vars' in data['message'])
|
self.assertFalse('merge_vars' in data['message'])
|
||||||
|
self.assertFalse('preserve_recipients' in data['message'])
|
||||||
self.assertFalse('recipient_metadata' in data['message'])
|
self.assertFalse('recipient_metadata' in data['message'])
|
||||||
|
self.assertFalse('return_path_domain' in data['message'])
|
||||||
|
self.assertFalse('signing_domain' in data['message'])
|
||||||
|
self.assertFalse('subaccount' in data['message'])
|
||||||
|
self.assertFalse('tracking_domain' in data['message'])
|
||||||
|
self.assertFalse('url_strip_qs' in data['message'])
|
||||||
|
self.assertFalse('view_content_link' in data['message'])
|
||||||
# Options at top level of api params (not in message dict):
|
# Options at top level of api params (not in message dict):
|
||||||
self.assertFalse('async' in data)
|
self.assertFalse('async' in data)
|
||||||
self.assertFalse('ip_pool' in data)
|
self.assertFalse('ip_pool' in data)
|
||||||
@@ -125,121 +210,20 @@ class MandrillBackendDjrillFeatureTests(MandrillBackendMockAPITestCase):
|
|||||||
with self.assertRaises(AnymailSerializationError):
|
with self.assertRaises(AnymailSerializationError):
|
||||||
self.message.send()
|
self.message.send()
|
||||||
|
|
||||||
|
@override_settings(ANYMAIL_MANDRILL_SEND_DEFAULTS={'subaccount': 'test_subaccount'})
|
||||||
@override_settings(ANYMAIL_SEND_DEFAULTS={
|
def test_subaccount_setting(self):
|
||||||
'from_name': 'Djrill Test',
|
"""Global, non-esp_extra version of subaccount default"""
|
||||||
'important': True,
|
with self.assertWarnsRegex(DeprecationWarning, 'subaccount'):
|
||||||
'auto_text': True,
|
mail.send_mail('Subject', 'Body', 'from@example.com', ['to@example.com'])
|
||||||
'auto_html': True,
|
|
||||||
'inline_css': True,
|
|
||||||
'url_strip_qs': True,
|
|
||||||
'preserve_recipients': True,
|
|
||||||
'view_content_link': True,
|
|
||||||
'subaccount': 'example-subaccount',
|
|
||||||
'tracking_domain': 'example.com',
|
|
||||||
'signing_domain': 'example.com',
|
|
||||||
'return_path_domain': 'example.com',
|
|
||||||
'google_analytics_domains': ['example.com/test'],
|
|
||||||
'google_analytics_campaign': ['UA-00000000-1'],
|
|
||||||
'merge_language': 'mailchimp',
|
|
||||||
'async': True,
|
|
||||||
'ip_pool': 'Pool1',
|
|
||||||
'invalid': 'invalid',
|
|
||||||
})
|
|
||||||
class MandrillBackendDjrillSendDefaultsTests(MandrillBackendMockAPITestCase):
|
|
||||||
"""Tests backend support for global SEND_DEFAULTS"""
|
|
||||||
|
|
||||||
def test_global_options(self):
|
|
||||||
"""Test that any global settings get passed through
|
|
||||||
"""
|
|
||||||
self.message.send()
|
|
||||||
data = self.get_api_call_json()
|
data = self.get_api_call_json()
|
||||||
self.assertEqual(data['message']['from_name'], 'Djrill Test')
|
self.assertEqual(data['message']['subaccount'], "test_subaccount")
|
||||||
self.assertTrue(data['message']['important'])
|
|
||||||
self.assertTrue(data['message']['auto_text'])
|
|
||||||
self.assertTrue(data['message']['auto_html'])
|
|
||||||
self.assertTrue(data['message']['inline_css'])
|
|
||||||
self.assertTrue(data['message']['url_strip_qs'])
|
|
||||||
self.assertTrue(data['message']['preserve_recipients'])
|
|
||||||
self.assertTrue(data['message']['view_content_link'])
|
|
||||||
self.assertEqual(data['message']['subaccount'], 'example-subaccount')
|
|
||||||
self.assertEqual(data['message']['tracking_domain'], 'example.com')
|
|
||||||
self.assertEqual(data['message']['signing_domain'], 'example.com')
|
|
||||||
self.assertEqual(data['message']['return_path_domain'], 'example.com')
|
|
||||||
self.assertEqual(data['message']['google_analytics_domains'], ['example.com/test'])
|
|
||||||
self.assertEqual(data['message']['google_analytics_campaign'], ['UA-00000000-1'])
|
|
||||||
self.assertEqual(data['message']['merge_language'], 'mailchimp')
|
|
||||||
self.assertFalse('recipient_metadata' in data['message'])
|
|
||||||
# Options at top level of api params (not in message dict):
|
|
||||||
self.assertTrue(data['async'])
|
|
||||||
self.assertEqual(data['ip_pool'], 'Pool1')
|
|
||||||
# Option that shouldn't be added
|
|
||||||
self.assertFalse('invalid' in data['message'])
|
|
||||||
|
|
||||||
def test_global_options_override(self):
|
@override_settings(ANYMAIL_MANDRILL_SEND_DEFAULTS={'subaccount': 'global_setting_subaccount'})
|
||||||
"""Test that manually settings options overrides global settings
|
def test_subaccount_message_overrides_setting(self):
|
||||||
"""
|
"""Global, non-esp_extra version of subaccount default"""
|
||||||
self.message.from_name = "override"
|
message = mail.EmailMessage('Subject', 'Body', 'from@example.com', ['to@example.com'])
|
||||||
self.message.important = False
|
message.subaccount = "individual_message_subaccount" # should override global setting
|
||||||
self.message.auto_text = False
|
with self.assertWarnsRegex(DeprecationWarning, 'subaccount'):
|
||||||
self.message.auto_html = False
|
message.send()
|
||||||
self.message.inline_css = False
|
|
||||||
self.message.url_strip_qs = False
|
|
||||||
self.message.preserve_recipients = False
|
|
||||||
self.message.view_content_link = False
|
|
||||||
self.message.subaccount = "override"
|
|
||||||
self.message.tracking_domain = "override.example.com"
|
|
||||||
self.message.signing_domain = "override.example.com"
|
|
||||||
self.message.return_path_domain = "override.example.com"
|
|
||||||
self.message.google_analytics_domains = ['override.example.com']
|
|
||||||
self.message.google_analytics_campaign = ['UA-99999999-1']
|
|
||||||
self.message.merge_language = 'handlebars'
|
|
||||||
self.message.async = False
|
|
||||||
self.message.ip_pool = "Bulk Pool"
|
|
||||||
self.message.send()
|
|
||||||
data = self.get_api_call_json()
|
data = self.get_api_call_json()
|
||||||
self.assertEqual(data['message']['from_name'], 'override')
|
self.assertEqual(data['message']['subaccount'], "individual_message_subaccount")
|
||||||
self.assertFalse(data['message']['important'])
|
|
||||||
self.assertFalse(data['message']['auto_text'])
|
|
||||||
self.assertFalse(data['message']['auto_html'])
|
|
||||||
self.assertFalse(data['message']['inline_css'])
|
|
||||||
self.assertFalse(data['message']['url_strip_qs'])
|
|
||||||
self.assertFalse(data['message']['preserve_recipients'])
|
|
||||||
self.assertFalse(data['message']['view_content_link'])
|
|
||||||
self.assertEqual(data['message']['subaccount'], 'override')
|
|
||||||
self.assertEqual(data['message']['tracking_domain'], 'override.example.com')
|
|
||||||
self.assertEqual(data['message']['signing_domain'], 'override.example.com')
|
|
||||||
self.assertEqual(data['message']['return_path_domain'], 'override.example.com')
|
|
||||||
self.assertEqual(data['message']['google_analytics_domains'], ['override.example.com'])
|
|
||||||
self.assertEqual(data['message']['google_analytics_campaign'], ['UA-99999999-1'])
|
|
||||||
self.assertEqual(data['message']['merge_language'], 'handlebars')
|
|
||||||
# Options at top level of api params (not in message dict):
|
|
||||||
self.assertFalse(data['async'])
|
|
||||||
self.assertEqual(data['ip_pool'], 'Bulk Pool')
|
|
||||||
|
|
||||||
|
|
||||||
class MandrillBackendDjrillTemplateTests(MandrillBackendMockAPITestCase):
|
|
||||||
"""Test backend support for ESP templating features"""
|
|
||||||
|
|
||||||
# Holdovers from Djrill, until we design Anymail's normalized esp-template support
|
|
||||||
|
|
||||||
def test_merge_language(self):
|
|
||||||
self.message.merge_language = "mailchimp"
|
|
||||||
self.message.send()
|
|
||||||
data = self.get_api_call_json()
|
|
||||||
self.assertEqual(data['message']['merge_language'], "mailchimp")
|
|
||||||
|
|
||||||
def test_template_content(self):
|
|
||||||
self.message.template_content = {
|
|
||||||
'HEADLINE': "<h1>Specials Just For *|FNAME|*</h1>",
|
|
||||||
'OFFER_BLOCK': "<p><em>Half off</em> all fruit</p>"
|
|
||||||
}
|
|
||||||
self.message.send()
|
|
||||||
data = self.get_api_call_json()
|
|
||||||
# Anymail expands simple python dicts into the more-verbose name/content
|
|
||||||
# structures the Mandrill API uses
|
|
||||||
self.assertEqual(data['template_content'],
|
|
||||||
[{'name': "HEADLINE",
|
|
||||||
'content': "<h1>Specials Just For *|FNAME|*</h1>"},
|
|
||||||
{'name': "OFFER_BLOCK",
|
|
||||||
'content': "<p><em>Half off</em> all fruit</p>"}])
|
|
||||||
|
|||||||
Reference in New Issue
Block a user