mirror of
https://github.com/pacnpal/django-anymail.git
synced 2025-12-20 11:51:05 -05:00
Rename exceptions
* Change Djrill -> Mandrill in exception names * Don't re-export at package level (import from anymail.exceptions, not from anymail)
This commit is contained in:
@@ -1,3 +1 @@
|
|||||||
from ._version import __version__, VERSION
|
from ._version import __version__, VERSION
|
||||||
from .exceptions import (MandrillAPIError, MandrillRecipientsRefused,
|
|
||||||
NotSerializableForMandrillError, NotSupportedByMandrillError)
|
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ from django.core.mail.backends.base import BaseEmailBackend
|
|||||||
from django.core.mail.message import sanitize_address, DEFAULT_ATTACHMENT_MIME_TYPE
|
from django.core.mail.message import sanitize_address, DEFAULT_ATTACHMENT_MIME_TYPE
|
||||||
|
|
||||||
from .._version import __version__
|
from .._version import __version__
|
||||||
from ..exceptions import (DjrillError, MandrillAPIError, MandrillRecipientsRefused,
|
from ..exceptions import (AnymailError, AnymailRequestsAPIError, AnymailRecipientsRefused,
|
||||||
NotSerializableForMandrillError, NotSupportedByMandrillError)
|
AnymailSerializationError, AnymailUnsupportedFeature)
|
||||||
|
|
||||||
|
|
||||||
class MandrillBackend(BaseEmailBackend):
|
class MandrillBackend(BaseEmailBackend):
|
||||||
@@ -127,8 +127,8 @@ class MandrillBackend(BaseEmailBackend):
|
|||||||
message.mandrill_response = self.parse_response(response, payload, message)
|
message.mandrill_response = self.parse_response(response, payload, message)
|
||||||
self.validate_response(message.mandrill_response, response, payload, message)
|
self.validate_response(message.mandrill_response, response, payload, message)
|
||||||
|
|
||||||
except DjrillError:
|
except AnymailError:
|
||||||
# every *expected* error is derived from DjrillError;
|
# every *expected* error is derived from AnymailError;
|
||||||
# we deliberately don't silence unexpected errors
|
# we deliberately don't silence unexpected errors
|
||||||
if not self.fail_silently:
|
if not self.fail_silently:
|
||||||
raise
|
raise
|
||||||
@@ -153,7 +153,7 @@ class MandrillBackend(BaseEmailBackend):
|
|||||||
payload is a dict that will become the Mandrill send data
|
payload is a dict that will become the Mandrill send data
|
||||||
message is an EmailMessage, possibly with additional Mandrill-specific attrs
|
message is an EmailMessage, possibly with additional Mandrill-specific attrs
|
||||||
|
|
||||||
Can raise NotSupportedByMandrillError for unsupported options in message.
|
Can raise AnymailUnsupportedFeature for unsupported options in message.
|
||||||
"""
|
"""
|
||||||
msg_dict = self._build_standard_message_dict(message)
|
msg_dict = self._build_standard_message_dict(message)
|
||||||
self._add_mandrill_options(message, msg_dict)
|
self._add_mandrill_options(message, msg_dict)
|
||||||
@@ -192,32 +192,32 @@ class MandrillBackend(BaseEmailBackend):
|
|||||||
message is the original EmailMessage
|
message is the original EmailMessage
|
||||||
return should be a requests.Response
|
return should be a requests.Response
|
||||||
|
|
||||||
Can raise NotSerializableForMandrillError if payload is not serializable
|
Can raise AnymailSerializationError if payload is not serializable
|
||||||
Can raise MandrillAPIError for HTTP errors in the post
|
Can raise AnymailRequestsAPIError for HTTP errors in the post
|
||||||
"""
|
"""
|
||||||
api_url = self.get_api_url(payload, message)
|
api_url = self.get_api_url(payload, message)
|
||||||
try:
|
try:
|
||||||
json_payload = self.serialize_payload(payload, message)
|
json_payload = self.serialize_payload(payload, message)
|
||||||
except TypeError as err:
|
except TypeError as err:
|
||||||
# Add some context to the "not JSON serializable" message
|
# Add some context to the "not JSON serializable" message
|
||||||
raise NotSerializableForMandrillError(
|
raise AnymailSerializationError(
|
||||||
orig_err=err, email_message=message, payload=payload)
|
orig_err=err, email_message=message, payload=payload)
|
||||||
|
|
||||||
response = self.session.post(api_url, data=json_payload)
|
response = self.session.post(api_url, data=json_payload)
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
raise MandrillAPIError(email_message=message, payload=payload, response=response)
|
raise AnymailRequestsAPIError(email_message=message, payload=payload, response=response)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def parse_response(self, response, payload, message):
|
def parse_response(self, response, payload, message):
|
||||||
"""Return parsed json from Mandrill API response
|
"""Return parsed json from Mandrill API response
|
||||||
|
|
||||||
Can raise MandrillAPIError if response is not valid JSON
|
Can raise AnymailRequestsAPIError if response is not valid JSON
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return response.json()
|
return response.json()
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise MandrillAPIError("Invalid JSON in Mandrill API response",
|
raise AnymailRequestsAPIError("Invalid JSON in Mandrill API response",
|
||||||
email_message=message, payload=payload, response=response)
|
email_message=message, payload=payload, response=response)
|
||||||
|
|
||||||
def validate_response(self, parsed_response, response, payload, message):
|
def validate_response(self, parsed_response, response, payload, message):
|
||||||
"""Validate parsed_response, raising exceptions for any problems.
|
"""Validate parsed_response, raising exceptions for any problems.
|
||||||
@@ -233,12 +233,12 @@ class MandrillBackend(BaseEmailBackend):
|
|||||||
try:
|
try:
|
||||||
recipient_status = [item["status"] for item in parsed_response]
|
recipient_status = [item["status"] for item in parsed_response]
|
||||||
except (KeyError, TypeError):
|
except (KeyError, TypeError):
|
||||||
raise MandrillAPIError("Invalid Mandrill API response format",
|
raise AnymailRequestsAPIError("Invalid Mandrill API response format",
|
||||||
email_message=message, payload=payload, response=response)
|
email_message=message, payload=payload, response=response)
|
||||||
# Error if *all* recipients are invalid or refused
|
# Error if *all* recipients are invalid or refused
|
||||||
# (This behavior parallels smtplib.SMTPRecipientsRefused from Django's SMTP EmailBackend)
|
# (This behavior parallels smtplib.SMTPRecipientsRefused from Django's SMTP EmailBackend)
|
||||||
if all([status in ('invalid', 'rejected') for status in recipient_status]):
|
if all([status in ('invalid', 'rejected') for status in recipient_status]):
|
||||||
raise MandrillRecipientsRefused(email_message=message, payload=payload, response=response)
|
raise AnymailRecipientsRefused(email_message=message, payload=payload, response=response)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Payload construction
|
# Payload construction
|
||||||
@@ -251,7 +251,7 @@ class MandrillBackend(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.
|
||||||
|
|
||||||
Raises NotSupportedByMandrillError for any standard EmailMessage
|
Raises AnymailUnsupportedFeature for any standard EmailMessage
|
||||||
features that cannot be accurately communicated to Mandrill.
|
features that cannot be accurately communicated to Mandrill.
|
||||||
"""
|
"""
|
||||||
sender = sanitize_address(message.from_email, message.encoding)
|
sender = sanitize_address(message.from_email, message.encoding)
|
||||||
@@ -381,14 +381,14 @@ class MandrillBackend(BaseEmailBackend):
|
|||||||
the HTML output for your email.
|
the HTML output for your email.
|
||||||
"""
|
"""
|
||||||
if len(message.alternatives) > 1:
|
if len(message.alternatives) > 1:
|
||||||
raise NotSupportedByMandrillError(
|
raise AnymailUnsupportedFeature(
|
||||||
"Too many alternatives attached to the message. "
|
"Too many alternatives attached to the message. "
|
||||||
"Mandrill only accepts plain text and html emails.",
|
"Mandrill only accepts plain text and html emails.",
|
||||||
email_message=message)
|
email_message=message)
|
||||||
|
|
||||||
(content, mimetype) = message.alternatives[0]
|
(content, mimetype) = message.alternatives[0]
|
||||||
if mimetype != 'text/html':
|
if mimetype != 'text/html':
|
||||||
raise NotSupportedByMandrillError(
|
raise AnymailUnsupportedFeature(
|
||||||
"Invalid alternative mimetype '%s'. "
|
"Invalid alternative mimetype '%s'. "
|
||||||
"Mandrill only accepts plain text and html emails."
|
"Mandrill only accepts plain text and html emails."
|
||||||
% mimetype,
|
% mimetype,
|
||||||
|
|||||||
@@ -2,28 +2,30 @@ import json
|
|||||||
from requests import HTTPError
|
from requests import HTTPError
|
||||||
|
|
||||||
|
|
||||||
class DjrillError(Exception):
|
class AnymailError(Exception):
|
||||||
"""Base class for exceptions raised by Djrill
|
"""Base class for exceptions raised by Anymail
|
||||||
|
|
||||||
Overrides __str__ to provide additional information about
|
Overrides __str__ to provide additional information about
|
||||||
Mandrill API call and response.
|
the ESP API call and response.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Optional kwargs:
|
Optional kwargs:
|
||||||
email_message: the original EmailMessage being sent
|
email_message: the original EmailMessage being sent
|
||||||
payload: data arg (*not* json-stringified) for the Mandrill send call
|
status_code: HTTP status code of response to ESP send call
|
||||||
|
payload: data arg (*not* json-stringified) for the ESP send call
|
||||||
response: requests.Response from the send call
|
response: requests.Response from the send call
|
||||||
"""
|
"""
|
||||||
self.email_message = kwargs.pop('email_message', None)
|
self.email_message = kwargs.pop('email_message', None)
|
||||||
self.payload = kwargs.pop('payload', None)
|
self.payload = kwargs.pop('payload', None)
|
||||||
|
self.status_code = kwargs.pop('status_code', None)
|
||||||
if isinstance(self, HTTPError):
|
if isinstance(self, HTTPError):
|
||||||
# must leave response in kwargs for HTTPError
|
# must leave response in kwargs for HTTPError
|
||||||
self.response = kwargs.get('response', None)
|
self.response = kwargs.get('response', None)
|
||||||
else:
|
else:
|
||||||
self.response = kwargs.pop('response', None)
|
self.response = kwargs.pop('response', None)
|
||||||
super(DjrillError, self).__init__(*args, **kwargs)
|
super(AnymailError, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
parts = [
|
parts = [
|
||||||
@@ -34,7 +36,7 @@ class DjrillError(Exception):
|
|||||||
return "\n".join(filter(None, parts))
|
return "\n".join(filter(None, parts))
|
||||||
|
|
||||||
def describe_send(self):
|
def describe_send(self):
|
||||||
"""Return a string describing the Mandrill send in self.payload, or None"""
|
"""Return a string describing the ESP send in self.payload, or None"""
|
||||||
if self.payload is None:
|
if self.payload is None:
|
||||||
return None
|
return None
|
||||||
description = "Sending a message"
|
description = "Sending a message"
|
||||||
@@ -50,10 +52,10 @@ class DjrillError(Exception):
|
|||||||
return description
|
return description
|
||||||
|
|
||||||
def describe_response(self):
|
def describe_response(self):
|
||||||
"""Return a formatted string of self.response, or None"""
|
"""Return a formatted string of self.status_code and response, or None"""
|
||||||
if self.response is None:
|
if self.status_code is None:
|
||||||
return None
|
return None
|
||||||
description = "Mandrill API response %d:" % self.response.status_code
|
description = "ESP API response %d:" % self.status_code
|
||||||
try:
|
try:
|
||||||
json_response = self.response.json()
|
json_response = self.response.json()
|
||||||
description += "\n" + json.dumps(json_response, indent=2)
|
description += "\n" + json.dumps(json_response, indent=2)
|
||||||
@@ -65,53 +67,56 @@ class DjrillError(Exception):
|
|||||||
return description
|
return description
|
||||||
|
|
||||||
|
|
||||||
class MandrillAPIError(DjrillError, HTTPError):
|
class AnymailAPIError(AnymailError):
|
||||||
"""Exception for unsuccessful response from Mandrill API."""
|
"""Exception for unsuccessful response from ESP's API."""
|
||||||
|
|
||||||
|
|
||||||
|
class AnymailRequestsAPIError(AnymailAPIError, HTTPError):
|
||||||
|
"""Exception for unsuccessful response from a requests API."""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(MandrillAPIError, self).__init__(*args, **kwargs)
|
super(AnymailRequestsAPIError, self).__init__(*args, **kwargs)
|
||||||
if self.response is not None:
|
if self.response is not None:
|
||||||
self.status_code = self.response.status_code
|
self.status_code = self.response.status_code
|
||||||
|
|
||||||
|
|
||||||
class MandrillRecipientsRefused(DjrillError):
|
class AnymailRecipientsRefused(AnymailError):
|
||||||
"""Exception for send where all recipients are invalid or rejected."""
|
"""Exception for send where all recipients are invalid or rejected."""
|
||||||
|
|
||||||
def __init__(self, message=None, *args, **kwargs):
|
def __init__(self, message=None, *args, **kwargs):
|
||||||
if message is None:
|
if message is None:
|
||||||
message = "All message recipients were rejected or invalid"
|
message = "All message recipients were rejected or invalid"
|
||||||
super(MandrillRecipientsRefused, self).__init__(message, *args, **kwargs)
|
super(AnymailRecipientsRefused, self).__init__(message, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class NotSupportedByMandrillError(DjrillError, ValueError):
|
class AnymailUnsupportedFeature(AnymailError, ValueError):
|
||||||
"""Exception for email features that Mandrill doesn't support.
|
"""Exception for Anymail features that the ESP doesn't support.
|
||||||
|
|
||||||
This is typically raised when attempting to send a Django EmailMessage that
|
This is typically raised when attempting to send a Django EmailMessage that
|
||||||
uses options or values you might expect to work, but that are silently
|
uses options or values you might expect to work, but that are silently
|
||||||
ignored by or can't be communicated to Mandrill's API. (E.g., non-HTML
|
ignored by or can't be communicated to the ESP's API.
|
||||||
alternative parts.)
|
|
||||||
|
|
||||||
It's generally *not* raised for Mandrill-specific features, like limitations
|
It's generally *not* raised for ESP-specific limitations, like the number
|
||||||
on Mandrill tag names or restrictions on from emails. (Djrill expects
|
of tags allowed on a message. (Anymail expects
|
||||||
Mandrill to return an API error for these where appropriate, and tries to
|
the ESP to return an API error for these where appropriate, and tries to
|
||||||
avoid duplicating Mandrill's validation logic locally.)
|
avoid duplicating each ESP's validation logic locally.)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class NotSerializableForMandrillError(DjrillError, TypeError):
|
class AnymailSerializationError(AnymailError, TypeError):
|
||||||
"""Exception for data that Djrill doesn't know how to convert to JSON.
|
"""Exception for data that Anymail can't serialize for the ESP's API.
|
||||||
|
|
||||||
This typically results from including something like a date or Decimal
|
This typically results from including something like a date or Decimal
|
||||||
in your merge_vars (or other Mandrill-specific EmailMessage option).
|
in your merge_vars.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# inherits from TypeError for backwards compatibility with Djrill 1.x
|
# inherits from TypeError for compatibility with JSON serialization error
|
||||||
|
|
||||||
def __init__(self, message=None, orig_err=None, *args, **kwargs):
|
def __init__(self, message=None, orig_err=None, *args, **kwargs):
|
||||||
if message is None:
|
if message is None:
|
||||||
message = "Don't know how to send this data to Mandrill. " \
|
message = "Don't know how to send this data to your ESP. " \
|
||||||
"Try converting it to a string or number first."
|
"Try converting it to a string or number first."
|
||||||
if orig_err is not None:
|
if orig_err is not None:
|
||||||
message += "\n%s" % str(orig_err)
|
message += "\n%s" % str(orig_err)
|
||||||
super(NotSerializableForMandrillError, self).__init__(message, *args, **kwargs)
|
super(AnymailSerializationError, self).__init__(message, *args, **kwargs)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from django.core import mail
|
|||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
from anymail import MandrillAPIError, MandrillRecipientsRefused
|
from anymail.exceptions import AnymailAPIError, AnymailRecipientsRefused
|
||||||
|
|
||||||
|
|
||||||
MANDRILL_TEST_API_KEY = os.getenv('MANDRILL_TEST_API_KEY')
|
MANDRILL_TEST_API_KEY = os.getenv('MANDRILL_TEST_API_KEY')
|
||||||
@@ -51,7 +51,7 @@ class DjrillIntegrationTests(TestCase):
|
|||||||
try:
|
try:
|
||||||
self.message.send()
|
self.message.send()
|
||||||
self.fail("This line will not be reached, because send() raised an exception")
|
self.fail("This line will not be reached, because send() raised an exception")
|
||||||
except MandrillAPIError as err:
|
except AnymailAPIError as err:
|
||||||
self.assertEqual(err.status_code, 500)
|
self.assertEqual(err.status_code, 500)
|
||||||
self.assertIn("email address is invalid", str(err))
|
self.assertIn("email address is invalid", str(err))
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ class DjrillIntegrationTests(TestCase):
|
|||||||
self.message.to = ['invalid@localhost']
|
self.message.to = ['invalid@localhost']
|
||||||
try:
|
try:
|
||||||
self.message.send()
|
self.message.send()
|
||||||
except MandrillRecipientsRefused:
|
except AnymailRecipientsRefused:
|
||||||
# Mandrill refused to deliver the mail -- message.mandrill_response will tell you why:
|
# Mandrill refused to deliver the mail -- message.mandrill_response will tell you why:
|
||||||
# noinspection PyUnresolvedReferences
|
# noinspection PyUnresolvedReferences
|
||||||
response = self.message.mandrill_response
|
response = self.message.mandrill_response
|
||||||
@@ -72,14 +72,14 @@ class DjrillIntegrationTests(TestCase):
|
|||||||
if response[0]['status'] == 'queued':
|
if response[0]['status'] == 'queued':
|
||||||
self.skipTest("Mandrill queued the send -- can't complete this test")
|
self.skipTest("Mandrill queued the send -- can't complete this test")
|
||||||
else:
|
else:
|
||||||
self.fail("Djrill did not raise MandrillRecipientsRefused for invalid recipient")
|
self.fail("Djrill did not raise AnymailRecipientsRefused for invalid recipient")
|
||||||
|
|
||||||
def test_rejected_to(self):
|
def test_rejected_to(self):
|
||||||
# Example of detecting when a recipient is on Mandrill's rejection blacklist
|
# Example of detecting when a recipient is on Mandrill's rejection blacklist
|
||||||
self.message.to = ['reject@test.mandrillapp.com']
|
self.message.to = ['reject@test.mandrillapp.com']
|
||||||
try:
|
try:
|
||||||
self.message.send()
|
self.message.send()
|
||||||
except MandrillRecipientsRefused:
|
except AnymailRecipientsRefused:
|
||||||
# Mandrill refused to deliver the mail -- message.mandrill_response will tell you why:
|
# Mandrill refused to deliver the mail -- message.mandrill_response will tell you why:
|
||||||
# noinspection PyUnresolvedReferences
|
# noinspection PyUnresolvedReferences
|
||||||
response = self.message.mandrill_response
|
response = self.message.mandrill_response
|
||||||
@@ -92,7 +92,7 @@ class DjrillIntegrationTests(TestCase):
|
|||||||
if response[0]['status'] == 'queued':
|
if response[0]['status'] == 'queued':
|
||||||
self.skipTest("Mandrill queued the send -- can't complete this test")
|
self.skipTest("Mandrill queued the send -- can't complete this test")
|
||||||
else:
|
else:
|
||||||
self.fail("Djrill did not raise MandrillRecipientsRefused for blacklist recipient")
|
self.fail("Djrill did not raise AnymailRecipientsRefused for blacklist recipient")
|
||||||
|
|
||||||
@override_settings(MANDRILL_API_KEY="Hey, that's not an API key!")
|
@override_settings(MANDRILL_API_KEY="Hey, that's not an API key!")
|
||||||
def test_invalid_api_key(self):
|
def test_invalid_api_key(self):
|
||||||
@@ -100,6 +100,6 @@ class DjrillIntegrationTests(TestCase):
|
|||||||
try:
|
try:
|
||||||
self.message.send()
|
self.message.send()
|
||||||
self.fail("This line will not be reached, because send() raised an exception")
|
self.fail("This line will not be reached, because send() raised an exception")
|
||||||
except MandrillAPIError as err:
|
except AnymailAPIError as err:
|
||||||
self.assertEqual(err.status_code, 500)
|
self.assertEqual(err.status_code, 500)
|
||||||
self.assertIn("Invalid API key", str(err))
|
self.assertIn("Invalid API key", str(err))
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ from django.core.mail import make_msgid
|
|||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
|
|
||||||
from anymail import (MandrillAPIError, MandrillRecipientsRefused,
|
from anymail.exceptions import (AnymailAPIError, AnymailRecipientsRefused,
|
||||||
NotSerializableForMandrillError, NotSupportedByMandrillError)
|
AnymailSerializationError, AnymailUnsupportedFeature)
|
||||||
|
|
||||||
from .mock_backend import DjrillBackendMockAPITestCase
|
from .mock_backend import DjrillBackendMockAPITestCase
|
||||||
|
|
||||||
@@ -275,14 +275,14 @@ class DjrillBackendTests(DjrillBackendMockAPITestCase):
|
|||||||
'from@example.com', ['to@example.com'])
|
'from@example.com', ['to@example.com'])
|
||||||
email.attach_alternative("<p>First html is OK</p>", "text/html")
|
email.attach_alternative("<p>First html is OK</p>", "text/html")
|
||||||
email.attach_alternative("<p>But not second html</p>", "text/html")
|
email.attach_alternative("<p>But not second html</p>", "text/html")
|
||||||
with self.assertRaises(NotSupportedByMandrillError):
|
with self.assertRaises(AnymailUnsupportedFeature):
|
||||||
email.send()
|
email.send()
|
||||||
|
|
||||||
# Only html alternatives allowed
|
# Only html alternatives allowed
|
||||||
email = mail.EmailMultiAlternatives('Subject', 'Body',
|
email = mail.EmailMultiAlternatives('Subject', 'Body',
|
||||||
'from@example.com', ['to@example.com'])
|
'from@example.com', ['to@example.com'])
|
||||||
email.attach_alternative("{'not': 'allowed'}", "application/json")
|
email.attach_alternative("{'not': 'allowed'}", "application/json")
|
||||||
with self.assertRaises(NotSupportedByMandrillError):
|
with self.assertRaises(AnymailUnsupportedFeature):
|
||||||
email.send()
|
email.send()
|
||||||
|
|
||||||
# Make sure fail_silently is respected
|
# Make sure fail_silently is respected
|
||||||
@@ -296,7 +296,7 @@ class DjrillBackendTests(DjrillBackendMockAPITestCase):
|
|||||||
|
|
||||||
def test_mandrill_api_failure(self):
|
def test_mandrill_api_failure(self):
|
||||||
self.mock_post.return_value = self.MockResponse(status_code=400)
|
self.mock_post.return_value = self.MockResponse(status_code=400)
|
||||||
with self.assertRaises(MandrillAPIError):
|
with self.assertRaises(AnymailAPIError):
|
||||||
sent = mail.send_mail('Subject', 'Body', 'from@example.com',
|
sent = mail.send_mail('Subject', 'Body', 'from@example.com',
|
||||||
['to@example.com'])
|
['to@example.com'])
|
||||||
self.assertEqual(sent, 0)
|
self.assertEqual(sent, 0)
|
||||||
@@ -319,17 +319,17 @@ class DjrillBackendTests(DjrillBackendMockAPITestCase):
|
|||||||
"message": "Helpful explanation from Mandrill"
|
"message": "Helpful explanation from Mandrill"
|
||||||
}"""
|
}"""
|
||||||
self.mock_post.return_value = self.MockResponse(status_code=400, raw=error_response)
|
self.mock_post.return_value = self.MockResponse(status_code=400, raw=error_response)
|
||||||
with self.assertRaisesMessage(MandrillAPIError, "Helpful explanation from Mandrill"):
|
with self.assertRaisesMessage(AnymailAPIError, "Helpful explanation from Mandrill"):
|
||||||
msg.send()
|
msg.send()
|
||||||
|
|
||||||
# Non-JSON error response:
|
# Non-JSON error response:
|
||||||
self.mock_post.return_value = self.MockResponse(status_code=500, raw=b"Invalid API key")
|
self.mock_post.return_value = self.MockResponse(status_code=500, raw=b"Invalid API key")
|
||||||
with self.assertRaisesMessage(MandrillAPIError, "Invalid API key"):
|
with self.assertRaisesMessage(AnymailAPIError, "Invalid API key"):
|
||||||
msg.send()
|
msg.send()
|
||||||
|
|
||||||
# No content in the error response:
|
# No content in the error response:
|
||||||
self.mock_post.return_value = self.MockResponse(status_code=502, raw=None)
|
self.mock_post.return_value = self.MockResponse(status_code=502, raw=None)
|
||||||
with self.assertRaises(MandrillAPIError):
|
with self.assertRaises(AnymailAPIError):
|
||||||
msg.send()
|
msg.send()
|
||||||
|
|
||||||
|
|
||||||
@@ -539,29 +539,29 @@ class DjrillMandrillFeatureTests(DjrillBackendMockAPITestCase):
|
|||||||
"""If the send succeeds, but a non-JSON API response, should raise an API exception"""
|
"""If the send succeeds, but a non-JSON API response, should raise an API exception"""
|
||||||
self.mock_post.return_value = self.MockResponse(status_code=500, raw=b"this isn't json")
|
self.mock_post.return_value = self.MockResponse(status_code=500, raw=b"this isn't json")
|
||||||
msg = mail.EmailMessage('Subject', 'Message', 'from@example.com', ['to1@example.com'],)
|
msg = mail.EmailMessage('Subject', 'Message', 'from@example.com', ['to1@example.com'],)
|
||||||
with self.assertRaises(MandrillAPIError):
|
with self.assertRaises(AnymailAPIError):
|
||||||
msg.send()
|
msg.send()
|
||||||
self.assertIsNone(msg.mandrill_response)
|
self.assertIsNone(msg.mandrill_response)
|
||||||
|
|
||||||
def test_json_serialization_errors(self):
|
def test_json_serialization_errors(self):
|
||||||
"""Try to provide more information about non-json-serializable data"""
|
"""Try to provide more information about non-json-serializable data"""
|
||||||
self.message.global_merge_vars = {'PRICE': Decimal('19.99')}
|
self.message.global_merge_vars = {'PRICE': Decimal('19.99')}
|
||||||
with self.assertRaises(NotSerializableForMandrillError) as cm:
|
with self.assertRaises(AnymailSerializationError) as cm:
|
||||||
self.message.send()
|
self.message.send()
|
||||||
err = cm.exception
|
err = cm.exception
|
||||||
self.assertTrue(isinstance(err, TypeError)) # Djrill 1.x re-raised TypeError from json.dumps
|
self.assertTrue(isinstance(err, TypeError)) # Djrill 1.x re-raised TypeError from json.dumps
|
||||||
self.assertStrContains(str(err), "Don't know how to send this data to Mandrill") # our added context
|
self.assertStrContains(str(err), "Don't know how to send this data to your ESP") # our added context
|
||||||
self.assertStrContains(str(err), "Decimal('19.99') is not JSON serializable") # original message
|
self.assertStrContains(str(err), "Decimal('19.99') is not JSON serializable") # original message
|
||||||
|
|
||||||
def test_dates_not_serialized(self):
|
def test_dates_not_serialized(self):
|
||||||
"""Pre-2.0 Djrill accidentally serialized dates to ISO"""
|
"""Pre-2.0 Djrill accidentally serialized dates to ISO"""
|
||||||
self.message.global_merge_vars = {'SHIP_DATE': date(2015, 12, 2)}
|
self.message.global_merge_vars = {'SHIP_DATE': date(2015, 12, 2)}
|
||||||
with self.assertRaises(NotSerializableForMandrillError):
|
with self.assertRaises(AnymailSerializationError):
|
||||||
self.message.send()
|
self.message.send()
|
||||||
|
|
||||||
|
|
||||||
class DjrillRecipientsRefusedTests(DjrillBackendMockAPITestCase):
|
class DjrillRecipientsRefusedTests(DjrillBackendMockAPITestCase):
|
||||||
"""Djrill raises MandrillRecipientsRefused when *all* recipients are rejected or invalid"""
|
"""Djrill raises AnymailRecipientsRefused when *all* recipients are rejected or invalid"""
|
||||||
|
|
||||||
def test_recipients_refused(self):
|
def test_recipients_refused(self):
|
||||||
msg = mail.EmailMessage('Subject', 'Body', 'from@example.com',
|
msg = mail.EmailMessage('Subject', 'Body', 'from@example.com',
|
||||||
@@ -569,7 +569,7 @@ class DjrillRecipientsRefusedTests(DjrillBackendMockAPITestCase):
|
|||||||
self.mock_post.return_value = self.MockResponse(status_code=200, raw=b"""
|
self.mock_post.return_value = self.MockResponse(status_code=200, raw=b"""
|
||||||
[{ "email": "invalid@localhost", "status": "invalid" },
|
[{ "email": "invalid@localhost", "status": "invalid" },
|
||||||
{ "email": "reject@test.mandrillapp.com", "status": "rejected" }]""")
|
{ "email": "reject@test.mandrillapp.com", "status": "rejected" }]""")
|
||||||
with self.assertRaises(MandrillRecipientsRefused):
|
with self.assertRaises(AnymailRecipientsRefused):
|
||||||
msg.send()
|
msg.send()
|
||||||
|
|
||||||
def test_fail_silently(self):
|
def test_fail_silently(self):
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from django.core import mail
|
from django.core import mail
|
||||||
|
|
||||||
from anymail import MandrillAPIError
|
from anymail.exceptions import AnymailAPIError
|
||||||
|
|
||||||
from .mock_backend import DjrillBackendMockAPITestCase
|
from .mock_backend import DjrillBackendMockAPITestCase
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ class DjrillMandrillSendTemplateTests(DjrillBackendMockAPITestCase):
|
|||||||
'from@example.com', ['to@example.com'])
|
'from@example.com', ['to@example.com'])
|
||||||
msg.template_name = "PERSONALIZED_SPECIALS"
|
msg.template_name = "PERSONALIZED_SPECIALS"
|
||||||
msg.use_template_from = True
|
msg.use_template_from = True
|
||||||
with self.assertRaises(MandrillAPIError):
|
with self.assertRaises(AnymailAPIError):
|
||||||
msg.send()
|
msg.send()
|
||||||
|
|
||||||
def test_send_template_without_subject_field(self):
|
def test_send_template_without_subject_field(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user