From e1c78ec19756d32d5fcdfe2248c7d9581ed55e2c Mon Sep 17 00:00:00 2001 From: Eric Hennings Date: Sun, 22 Dec 2013 14:12:57 -0800 Subject: [PATCH] Add the Mandrill send API response to EmailMessage as a property, mandrill_response, when a message is sent. For errors, set mandrill_response to None. Add tests & docs. --- djrill/mail/backends/djrill.py | 9 ++++++++- djrill/tests/mock_backend.py | 6 +++++- djrill/tests/test_mandrill_send.py | 18 ++++++++++++++++- docs/usage/sending_mail.rst | 32 ++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 3 deletions(-) diff --git a/djrill/mail/backends/djrill.py b/djrill/mail/backends/djrill.py index a3a23f3..0be5e15 100644 --- a/djrill/mail/backends/djrill.py +++ b/djrill/mail/backends/djrill.py @@ -105,6 +105,10 @@ class DjrillBackend(BaseEmailBackend): response = requests.post(api_url, data=json.dumps(api_params, cls=JSONDateUTCEncoder)) if response.status_code != 200: + + # add a mandrill_response for the sake of being explicit + message.mandrill_response = None + if not self.fail_silently: raise MandrillAPIError( status_code=response.status_code, @@ -112,6 +116,10 @@ class DjrillBackend(BaseEmailBackend): log_message="Failed to send a message to %s, from %s" % (msg_dict['to'], msg_dict['from_email'])) return False + + # add the response from mandrill to the EmailMessage so callers can inspect it + message.mandrill_response = response.json() + return True def _build_standard_message_dict(self, message): @@ -302,4 +310,3 @@ class DjrillBackend(BaseEmailBackend): 'content': content_b64.decode('ascii'), } return mandrill_attachment, is_embedded_image - diff --git a/djrill/tests/mock_backend.py b/djrill/tests/mock_backend.py index f697177..2fc0389 100644 --- a/djrill/tests/mock_backend.py +++ b/djrill/tests/mock_backend.py @@ -10,9 +10,13 @@ class DjrillBackendMockAPITestCase(TestCase): class MockResponse: """requests.post return value mock sufficient for DjrillBackend""" - def __init__(self, status_code=200, content="{}"): + def __init__(self, status_code=200, content="{}", json=['']): self.status_code = status_code self.content = content + self._json = json + + def json(self): + return self._json def setUp(self): self.patch = patch('requests.post', autospec=True) diff --git a/djrill/tests/test_mandrill_send.py b/djrill/tests/test_mandrill_send.py index 74973cd..ada91df 100644 --- a/djrill/tests/test_mandrill_send.py +++ b/djrill/tests/test_mandrill_send.py @@ -10,9 +10,9 @@ from django.core.exceptions import ImproperlyConfigured from django.core.mail import make_msgid from djrill import MandrillAPIError, NotSupportedByMandrillError +from djrill.mail.backends.djrill import DjrillBackend from djrill.tests.mock_backend import DjrillBackendMockAPITestCase - def decode_att(att): """Returns the original data from base64-encoded attachment content""" return b64decode(att.encode('ascii')) @@ -459,4 +459,20 @@ class DjrillMandrillFeatureTests(DjrillBackendMockAPITestCase): self.assertFalse('async' in data) self.assertFalse('ip_pool' in data) + def test_send_attaches_mandrill_response(self): + """ The mandrill_response should be attached to the message when it is sent """ + response = [{u'status': u'sent', u'_id': u'd2dc8a04fedb463398d2c124fd0f1774', + u'email': u'someone@example.com', u'reject_reason': None}] + self.mock_post.return_value = self.MockResponse(json=response) + msg = mail.EmailMessage('Subject', 'Message', 'from@example.com', ['to1@example.com'],) + sent = msg.send() + self.assertEqual(sent, 1) + self.assertEqual(msg.mandrill_response, response) + def test_send_failed_mandrill_response(self): + """ If the send fails, mandrill_response should be set to None """ + self.mock_post.return_value = self.MockResponse(status_code=500) + msg = mail.EmailMessage('Subject', 'Message', 'from@example.com', ['to1@example.com'],) + sent = msg.send(fail_silently=True) + self.assertEqual(sent, 0) + self.assertIsNone(msg.mandrill_response) \ No newline at end of file diff --git a/docs/usage/sending_mail.rst b/docs/usage/sending_mail.rst index 50a3d21..3909ff7 100644 --- a/docs/usage/sending_mail.rst +++ b/docs/usage/sending_mail.rst @@ -272,6 +272,38 @@ If you have questions about the python syntax for any of these properties, see :class:`DjrillMandrillFeatureTests` in :file:`tests/test_mandrill_send.py` for examples. + +.. _mandrill-response: + +Mandrill Response +--------------------------------- +A ``mandrill_response`` property is added to each :class:`~django.core.mail.EmailMessage` that you +send. This allows you to retrieve message ids, initial status information and more. + +For an EmailMessage that is successfully sent to one or more email addresses, ``mandrill_response`` will +be set to a ``list`` of ``dict``, where each entry has info for one email address. See the Mandrill docs for the +/messages/send api for full details. + +For example, to get the Mandrill message id for a sent email you might do this:: + + msg = EmailMultiAlternatives(subject="subject", body="body", + from_email="sender@example.com",to=["someone@example.com"]) + msg.send() + response = msg.mandrill_response[0] + mandrill_id = response['_id'] + +For this example, msg.mandrill_response might look like this:: + + msg.mandrill_response = [ + { + "email": "someone@example.com", + "status": "sent", + "_id": "abc123abc123abc123abc123abc123" + } + ] + +If an error is returned by Mandrill while sending the message then ``mandrill_response`` will be set to None. + .. _djrill-exceptions: Exceptions