mirror of
https://github.com/pacnpal/django-anymail.git
synced 2025-12-20 20:01:05 -05:00
Merge pull request #7 from medmunds/core_message_objects
Support Django standard EmailMessage objects
This commit is contained in:
@@ -26,7 +26,7 @@ class DjrillBackend(BaseEmailBackend):
|
|||||||
Mandrill API Email Backend
|
Mandrill API Email Backend
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, fail_silently=False, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
Set the API key, API url and set the action url.
|
Set the API key, API url and set the action url.
|
||||||
"""
|
"""
|
||||||
@@ -71,8 +71,13 @@ class DjrillBackend(BaseEmailBackend):
|
|||||||
if getattr(message, "alternative_subtype", None):
|
if getattr(message, "alternative_subtype", None):
|
||||||
if message.alternative_subtype == "mandrill":
|
if message.alternative_subtype == "mandrill":
|
||||||
self._build_advanced_message_dict(message)
|
self._build_advanced_message_dict(message)
|
||||||
if message.alternatives:
|
try:
|
||||||
self._add_alternatives(message)
|
if getattr(message, 'alternatives', None):
|
||||||
|
self._add_alternatives(message)
|
||||||
|
except ValueError:
|
||||||
|
if not self.fail_silently:
|
||||||
|
raise
|
||||||
|
return False
|
||||||
|
|
||||||
djrill_it = requests.post(self.api_action, data=json.dumps({
|
djrill_it = requests.post(self.api_action, data=json.dumps({
|
||||||
"key": self.api_key,
|
"key": self.api_key,
|
||||||
@@ -96,46 +101,54 @@ class DjrillBackend(BaseEmailBackend):
|
|||||||
use by default. Standard text email messages sent through Django will
|
use by default. Standard text email messages sent through Django will
|
||||||
still work through Mandrill.
|
still work through Mandrill.
|
||||||
"""
|
"""
|
||||||
return {
|
msg_dict = {
|
||||||
"text": message.body,
|
"text": message.body,
|
||||||
"subject": message.subject,
|
"subject": message.subject,
|
||||||
"from_email": self.sender,
|
"from_email": self.sender,
|
||||||
"to": self.recipients
|
"to": self.recipients
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if message.extra_headers:
|
||||||
|
accepted_headers = {}
|
||||||
|
for k in message.extra_headers.keys():
|
||||||
|
if k.startswith("X-") or k == "Reply-To":
|
||||||
|
accepted_headers.update(
|
||||||
|
{"%s" % k: message.extra_headers[k]})
|
||||||
|
msg_dict.update({"headers": accepted_headers})
|
||||||
|
|
||||||
|
return msg_dict
|
||||||
|
|
||||||
def _build_advanced_message_dict(self, message):
|
def _build_advanced_message_dict(self, message):
|
||||||
"""
|
"""
|
||||||
Builds advanced message dict and attaches any accepted extra headers.
|
Builds advanced message dict
|
||||||
"""
|
"""
|
||||||
self.msg_dict.update({
|
self.msg_dict.update({
|
||||||
"from_name": message.from_name,
|
"from_name": message.from_name,
|
||||||
"tags": message.tags,
|
"tags": message.tags,
|
||||||
"track_opens": message.track_opens,
|
"track_opens": message.track_opens,
|
||||||
|
"track_clicks": message.track_clicks
|
||||||
})
|
})
|
||||||
|
|
||||||
if message.extra_headers:
|
|
||||||
accepted_headers = {}
|
|
||||||
|
|
||||||
for k in message.extra_headers.keys():
|
|
||||||
if k.startswith("X-") or k == "Reply-To":
|
|
||||||
accepted_headers.update(
|
|
||||||
{"%s" % k: message.extra_headers[k]})
|
|
||||||
self.msg_dict.update({"headers": accepted_headers})
|
|
||||||
|
|
||||||
def _add_alternatives(self, message):
|
def _add_alternatives(self, message):
|
||||||
"""
|
"""
|
||||||
There can be only one! ... alternative attachment.
|
There can be only one! ... alternative attachment, and it must be text/html.
|
||||||
|
|
||||||
Since mandrill does not accept image attachments or anything other
|
Since mandrill does not accept image attachments or anything other
|
||||||
than HTML, the assumption is the only thing you are attaching is
|
than HTML, the assumption is the only thing you are attaching is
|
||||||
the HTML output for your email.
|
the HTML output for your email.
|
||||||
"""
|
"""
|
||||||
if len(message.alternatives) > 1:
|
if len(message.alternatives) > 1:
|
||||||
raise ImproperlyConfigured(
|
raise ValueError(
|
||||||
"Mandrill only accepts plain text and html emails. Please "
|
"Too many alternatives attached to the message. "
|
||||||
"check the alternatives you have attached to your message.")
|
"Mandrill only accepts plain text and html emails.")
|
||||||
|
|
||||||
|
(content, mimetype) = message.alternatives[0]
|
||||||
|
if mimetype != 'text/html':
|
||||||
|
raise ValueError("Invalid alternative mimetype '%s'. "
|
||||||
|
"Mandrill only accepts plain text and html emails."
|
||||||
|
% mimetype)
|
||||||
|
|
||||||
self.msg_dict.update({
|
self.msg_dict.update({
|
||||||
"html": message.alternatives[0][0],
|
"html": content
|
||||||
"track_clicks": message.track_clicks
|
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -65,6 +65,69 @@ class DjrillBackendTests(DjrillBackendMockAPITestCase):
|
|||||||
mail.send_mail('Subject', 'Message', 'from@example.com',
|
mail.send_mail('Subject', 'Message', 'from@example.com',
|
||||||
['to@example.com'])
|
['to@example.com'])
|
||||||
|
|
||||||
|
def test_email_message(self):
|
||||||
|
email = mail.EmailMessage('Subject', 'Body goes here',
|
||||||
|
'from@example.com',
|
||||||
|
['to1@example.com', 'Also To <to2@example.com>'],
|
||||||
|
bcc=['bcc1@example.com', 'Also BCC <bcc2@example.com>'],
|
||||||
|
cc=['cc1@example.com', 'Also CC <cc2@example.com>'],
|
||||||
|
headers={'Reply-To': 'another@example.com',
|
||||||
|
'X-MyHeader': 'my value',
|
||||||
|
'Errors-To': 'silently stripped'})
|
||||||
|
email.send()
|
||||||
|
data = self.get_api_call_data()
|
||||||
|
self.assertEqual(data['message']['subject'], "Subject")
|
||||||
|
self.assertEqual(data['message']['text'], "Body goes here")
|
||||||
|
self.assertEqual(data['message']['from_email'], "from@example.com")
|
||||||
|
self.assertEqual(data['message']['headers'],
|
||||||
|
{ 'Reply-To': 'another@example.com', 'X-MyHeader': 'my value' })
|
||||||
|
# Mandrill doesn't have a notion of cc, and only allows a single bcc.
|
||||||
|
# Djrill just treats cc and bcc as though they were "to" addresses,
|
||||||
|
# which may or may not be what you want.
|
||||||
|
self.assertEqual(len(data['message']['to']), 6)
|
||||||
|
self.assertEqual(data['message']['to'][0]['email'], "to1@example.com")
|
||||||
|
self.assertEqual(data['message']['to'][1]['email'], "to2@example.com")
|
||||||
|
self.assertEqual(data['message']['to'][2]['email'], "cc1@example.com")
|
||||||
|
self.assertEqual(data['message']['to'][3]['email'], "cc2@example.com")
|
||||||
|
self.assertEqual(data['message']['to'][4]['email'], "bcc1@example.com")
|
||||||
|
self.assertEqual(data['message']['to'][5]['email'], "bcc2@example.com")
|
||||||
|
|
||||||
|
def test_html_message(self):
|
||||||
|
text_content = 'This is an important message.'
|
||||||
|
html_content = '<p>This is an <strong>important</strong> message.</p>'
|
||||||
|
email = mail.EmailMultiAlternatives('Subject', text_content,
|
||||||
|
'from@example.com', ['to@example.com'])
|
||||||
|
email.attach_alternative(html_content, "text/html")
|
||||||
|
email.send()
|
||||||
|
data = self.get_api_call_data()
|
||||||
|
self.assertEqual(data['message']['text'], text_content)
|
||||||
|
self.assertEqual(data['message']['html'], html_content)
|
||||||
|
|
||||||
|
def test_alternative_errors(self):
|
||||||
|
# Multiple alternatives not allowed
|
||||||
|
email = mail.EmailMultiAlternatives('Subject', 'Body',
|
||||||
|
'from@example.com', ['to@example.com'])
|
||||||
|
email.attach_alternative("<p>First html is OK</p>", "text/html")
|
||||||
|
email.attach_alternative("<p>But not second html</p>", "text/html")
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
email.send()
|
||||||
|
|
||||||
|
# Only html alternatives allowed
|
||||||
|
email = mail.EmailMultiAlternatives('Subject', 'Body',
|
||||||
|
'from@example.com', ['to@example.com'])
|
||||||
|
email.attach_alternative("{'not': 'allowed'}", "application/json")
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
email.send()
|
||||||
|
|
||||||
|
# Make sure fail_silently is respected
|
||||||
|
email = mail.EmailMultiAlternatives('Subject', 'Body',
|
||||||
|
'from@example.com', ['to@example.com'])
|
||||||
|
email.attach_alternative("{'not': 'allowed'}", "application/json")
|
||||||
|
sent = email.send(fail_silently=True)
|
||||||
|
self.assertFalse(self.mock_post.called,
|
||||||
|
msg="Mandrill API should not be called when send fails silently")
|
||||||
|
self.assertEqual(sent, 0)
|
||||||
|
|
||||||
|
|
||||||
class DjrillMessageTests(TestCase):
|
class DjrillMessageTests(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user