mirror of
https://github.com/pacnpal/django-anymail.git
synced 2025-12-20 03:41:05 -05:00
Uniform settings handling
For MANDRILL_API_KEY (e.g.,), look for these settings:
* ANYMAIL = { 'MANDRILL_API_KEY': '...' }
* ANYMAIL_MANDRILL_API_KEY = "..."
* MANDRILL_API_KEY = "..."
(the "bare" third version is used only for settings that
might be reasonably shared with other apps, like api keys)
This commit is contained in:
@@ -8,7 +8,7 @@ from django.conf import settings
|
||||
from django.core.mail.backends.base import BaseEmailBackend
|
||||
|
||||
from ..exceptions import AnymailError, AnymailRequestsAPIError, AnymailSerializationError, AnymailUnsupportedFeature
|
||||
from ..utils import Attachment, ParsedEmail, UNSET, combine, last
|
||||
from ..utils import Attachment, ParsedEmail, UNSET, combine, last, get_anymail_setting
|
||||
from .._version import __version__
|
||||
|
||||
|
||||
@@ -19,7 +19,17 @@ class AnymailBaseBackend(BaseEmailBackend):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(AnymailBaseBackend, self).__init__(*args, **kwargs)
|
||||
self.send_defaults = getattr(settings, "ANYMAIL_SEND_DEFAULTS", {})
|
||||
|
||||
self.unsupported_feature_errors = get_anymail_setting("UNSUPPORTED_FEATURE_ERRORS", True)
|
||||
self.ignore_recipient_status = get_anymail_setting("IGNORE_RECIPIENT_STATUS", False)
|
||||
|
||||
# Merge SEND_DEFAULTS and <esp_name>_SEND_DEFAULTS settings
|
||||
send_defaults = get_anymail_setting("SEND_DEFAULTS", {})
|
||||
esp_send_defaults = get_anymail_setting("%s_SEND_DEFAULTS" % self.esp_name.upper(), None)
|
||||
if esp_send_defaults is not None:
|
||||
send_defaults = send_defaults.copy()
|
||||
send_defaults.update(esp_send_defaults)
|
||||
self.send_defaults = send_defaults
|
||||
|
||||
def open(self):
|
||||
"""
|
||||
@@ -296,9 +306,9 @@ class BasePayload(object):
|
||||
setter(value)
|
||||
|
||||
def unsupported_feature(self, feature):
|
||||
# future: check settings.ANYMAIL_UNSUPPORTED_FEATURE_ERRORS
|
||||
raise AnymailUnsupportedFeature("%s does not support %s" % (self.esp_name, feature),
|
||||
email_message=self.message)
|
||||
if self.backend.unsupported_feature_errors:
|
||||
raise AnymailUnsupportedFeature("%s does not support %s" % (self.esp_name, feature),
|
||||
email_message=self.message, payload=self, backend=self.backend)
|
||||
|
||||
#
|
||||
# Attribute converters
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
from datetime import date, datetime
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from ..exceptions import (AnymailImproperlyConfigured, AnymailRequestsAPIError,
|
||||
AnymailRecipientsRefused, AnymailUnsupportedFeature)
|
||||
from ..utils import last, combine
|
||||
from ..exceptions import AnymailRequestsAPIError, AnymailRecipientsRefused
|
||||
from ..utils import last, combine, get_anymail_setting
|
||||
|
||||
from .base import AnymailRequestsBackend, RequestsPayload
|
||||
|
||||
@@ -16,33 +13,12 @@ class MandrillBackend(AnymailRequestsBackend):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
"""Init options from Django settings"""
|
||||
api_url = getattr(settings, "MANDRILL_API_URL", "https://mandrillapp.com/api/1.0")
|
||||
self.api_key = get_anymail_setting('MANDRILL_API_KEY', allow_bare=True)
|
||||
api_url = get_anymail_setting("MANDRILL_API_URL", "https://mandrillapp.com/api/1.0")
|
||||
if not api_url.endswith("/"):
|
||||
api_url += "/"
|
||||
|
||||
super(MandrillBackend, self).__init__(api_url, **kwargs)
|
||||
|
||||
try:
|
||||
self.api_key = settings.MANDRILL_API_KEY
|
||||
except AttributeError:
|
||||
raise AnymailImproperlyConfigured("Set MANDRILL_API_KEY in settings.py to use Anymail Mandrill backend")
|
||||
|
||||
# Djrill compat! MANDRILL_SETTINGS
|
||||
try:
|
||||
self.send_defaults.update(settings.MANDRILL_SETTINGS)
|
||||
except AttributeError:
|
||||
pass # no MANDRILL_SETTINGS setting
|
||||
except (TypeError, ValueError): # e.g., not enumerable
|
||||
raise AnymailImproperlyConfigured("MANDRILL_SETTINGS must be a dict or mapping")
|
||||
|
||||
# Djrill compat! MANDRILL_SUBACCOUNT
|
||||
try:
|
||||
self.send_defaults["subaccount"] = settings.MANDRILL_SUBACCOUNT
|
||||
except AttributeError:
|
||||
pass # no MANDRILL_SUBACCOUNT setting
|
||||
|
||||
self.ignore_recipient_status = getattr(settings, "MANDRILL_IGNORE_RECIPIENT_STATUS", False)
|
||||
|
||||
def build_message_payload(self, message):
|
||||
return MandrillPayload(message, self.send_defaults, self)
|
||||
|
||||
@@ -151,18 +127,9 @@ class MandrillPayload(RequestsPayload):
|
||||
|
||||
def add_alternative(self, content, mimetype):
|
||||
if mimetype != 'text/html':
|
||||
raise AnymailUnsupportedFeature(
|
||||
"Invalid alternative mimetype '%s'. "
|
||||
"Mandrill only accepts plain text and html emails."
|
||||
% mimetype,
|
||||
email_message=self.message)
|
||||
|
||||
self.unsupported_feature("alternative part with mimetype '%s'" % mimetype)
|
||||
if "html" in self.data["message"]:
|
||||
raise AnymailUnsupportedFeature(
|
||||
"Too many alternatives attached to the message. "
|
||||
"Mandrill only accepts plain text and html emails.",
|
||||
email_message=self.message)
|
||||
|
||||
self.unsupported_feature("multiple html parts")
|
||||
self.data["message"]["html"] = content
|
||||
|
||||
def add_attachment(self, attachment):
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
import json
|
||||
from requests import HTTPError
|
||||
|
||||
@@ -68,10 +67,6 @@ class AnymailError(Exception):
|
||||
return description
|
||||
|
||||
|
||||
class AnymailImproperlyConfigured(AnymailError, ImproperlyConfigured):
|
||||
"""Exception for configuration problems"""
|
||||
|
||||
|
||||
class AnymailAPIError(AnymailError):
|
||||
"""Exception for unsuccessful response from ESP's API."""
|
||||
|
||||
|
||||
1
anymail/models.py
Normal file
1
anymail/models.py
Normal file
@@ -0,0 +1 @@
|
||||
# this empty models.py is here for Django testrunner compatibility pre Django 1.6
|
||||
@@ -603,7 +603,7 @@ class DjrillRecipientsRefusedTests(DjrillBackendMockAPITestCase):
|
||||
sent = msg.send()
|
||||
self.assertEqual(sent, 1) # one message sent, successfully, to 2 of 4 recipients
|
||||
|
||||
@override_settings(MANDRILL_IGNORE_RECIPIENT_STATUS=True)
|
||||
@override_settings(ANYMAIL_IGNORE_RECIPIENT_STATUS=True)
|
||||
def test_settings_override(self):
|
||||
"""Setting restores Djrill 1.x behavior"""
|
||||
self.mock_post.return_value = self.MockResponse(status_code=200, raw=b"""
|
||||
|
||||
@@ -12,31 +12,16 @@ class DjrillMandrillSubaccountTests(DjrillBackendMockAPITestCase):
|
||||
data = self.get_api_call_data()
|
||||
self.assertFalse('subaccount' in data['message'])
|
||||
|
||||
@override_settings(MANDRILL_SETTINGS={'subaccount': 'test_subaccount'})
|
||||
@override_settings(ANYMAIL_MANDRILL_SEND_DEFAULTS={'subaccount': 'test_subaccount'})
|
||||
def test_subaccount_setting(self):
|
||||
mail.send_mail('Subject', 'Body', 'from@example.com', ['to@example.com'])
|
||||
data = self.get_api_call_data()
|
||||
self.assertEqual(data['message']['subaccount'], "test_subaccount")
|
||||
|
||||
@override_settings(MANDRILL_SETTINGS={'subaccount': 'global_setting_subaccount'})
|
||||
@override_settings(ANYMAIL_MANDRILL_SEND_DEFAULTS={'subaccount': 'global_setting_subaccount'})
|
||||
def test_subaccount_message_overrides_setting(self):
|
||||
message = mail.EmailMessage('Subject', 'Body', 'from@example.com', ['to@example.com'])
|
||||
message.subaccount = "individual_message_subaccount" # should override global setting
|
||||
message.send()
|
||||
data = self.get_api_call_data()
|
||||
self.assertEqual(data['message']['subaccount'], "individual_message_subaccount")
|
||||
|
||||
# Djrill 1.x offered dedicated MANDRILL_SUBACCOUNT setting.
|
||||
# In Djrill 2.x, you should use the MANDRILL_SETTINGS dict as in the earlier tests.
|
||||
# But we still support the old setting for compatibility:
|
||||
@override_settings(MANDRILL_SUBACCOUNT="legacy_setting_subaccount")
|
||||
def test_subaccount_legacy_setting(self):
|
||||
mail.send_mail('Subject', 'Body', 'from@example.com', ['to@example.com'])
|
||||
data = self.get_api_call_data()
|
||||
self.assertEqual(data['message']['subaccount'], "legacy_setting_subaccount")
|
||||
|
||||
message = mail.EmailMessage('Subject', 'Body', 'from@example.com', ['to@example.com'])
|
||||
message.subaccount = "individual_message_subaccount" # should override legacy setting
|
||||
message.send()
|
||||
data = self.get_api_call_data()
|
||||
self.assertEqual(data['message']['subaccount'], "individual_message_subaccount")
|
||||
|
||||
@@ -4,6 +4,8 @@ from email.mime.base import MIMEBase
|
||||
from email.utils import parseaddr
|
||||
|
||||
import six
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.core.mail.message import sanitize_address, DEFAULT_ATTACHMENT_MIME_TYPE
|
||||
|
||||
|
||||
@@ -133,3 +135,43 @@ class Attachment(object):
|
||||
if isinstance(content, six.text_type):
|
||||
content = content.encode(self.encoding)
|
||||
return b64encode(content).decode("ascii")
|
||||
|
||||
|
||||
def get_anymail_setting(setting, default=UNSET, allow_bare=False):
|
||||
"""Returns a Django Anymail setting.
|
||||
|
||||
Returns first of:
|
||||
- settings.ANYMAIL[setting]
|
||||
- settings.ANYMAIL_<setting>
|
||||
- settings.<setting> (only if allow_bare)
|
||||
- default if provided; else raises ImproperlyConfigured
|
||||
|
||||
ANYMAIL = { "MAILGUN_SEND_DEFAULTS" : { ... }, ... }
|
||||
ANYMAIL_MAILGUN_SEND_DEFAULTS = { ... }
|
||||
|
||||
If allow_bare, allows settings.<setting> without the ANYMAIL_ prefix:
|
||||
ANYMAIL = { "MAILGUN_API_KEY": "xyz", ... }
|
||||
ANYMAIL_MAILGUN_API_KEY = "xyz"
|
||||
MAILGUN_API_KEY = "xyz"
|
||||
"""
|
||||
|
||||
anymail_setting = "ANYMAIL_%s" % setting
|
||||
try:
|
||||
return settings.ANYMAIL[setting]
|
||||
except (AttributeError, KeyError):
|
||||
try:
|
||||
return getattr(settings, anymail_setting)
|
||||
except AttributeError:
|
||||
if allow_bare:
|
||||
try:
|
||||
return getattr(settings, setting)
|
||||
except AttributeError:
|
||||
pass
|
||||
if default is UNSET:
|
||||
message = "You must set %s or ANYMAIL = {'%s': ...}" % (anymail_setting, setting)
|
||||
if allow_bare:
|
||||
message += " or %s" % setting
|
||||
message += " in your Django settings"
|
||||
raise ImproperlyConfigured(message)
|
||||
else:
|
||||
return default
|
||||
|
||||
Reference in New Issue
Block a user