mirror of
https://github.com/pacnpal/django-anymail.git
synced 2025-12-20 03:41:05 -05:00
Mailgun: Add MAILGUN_SENDER_DOMAIN setting
Allow custom MAILGUN_SENDER_DOMAIN in Anymail settings. (Replaces need to use global esp_extra.) Improve docs to cover cases where this is needed. (esp_extra sender_domain is still supported for overriding individual messages.) Fixes #26.
This commit is contained in:
@@ -100,7 +100,9 @@ or SparkPost or any other supported ESP where you see "mailgun":
|
|||||||
)
|
)
|
||||||
|
|
||||||
ANYMAIL = {
|
ANYMAIL = {
|
||||||
|
# (exact settings here depend on your ESP...)
|
||||||
"MAILGUN_API_KEY": "<your Mailgun key>",
|
"MAILGUN_API_KEY": "<your Mailgun key>",
|
||||||
|
"MAILGUN_SENDER_DOMAIN": 'mg.example.com', # your Mailgun domain, if needed
|
||||||
}
|
}
|
||||||
EMAIL_BACKEND = "anymail.backends.mailgun.MailgunBackend" # or sendgrid.SendGridBackend, or...
|
EMAIL_BACKEND = "anymail.backends.mailgun.MailgunBackend" # or sendgrid.SendGridBackend, or...
|
||||||
DEFAULT_FROM_EMAIL = "you@example.com" # if you don't already have this in settings
|
DEFAULT_FROM_EMAIL = "you@example.com" # if you don't already have this in settings
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ class MailgunBackend(AnymailRequestsBackend):
|
|||||||
"""Init options from Django settings"""
|
"""Init options from Django settings"""
|
||||||
esp_name = self.esp_name
|
esp_name = self.esp_name
|
||||||
self.api_key = get_anymail_setting('api_key', esp_name=esp_name, kwargs=kwargs, allow_bare=True)
|
self.api_key = get_anymail_setting('api_key', esp_name=esp_name, kwargs=kwargs, allow_bare=True)
|
||||||
|
self.sender_domain = get_anymail_setting('sender_domain', esp_name=esp_name, kwargs=kwargs,
|
||||||
|
allow_bare=True, default=None)
|
||||||
api_url = get_anymail_setting('api_url', esp_name=esp_name, kwargs=kwargs,
|
api_url = get_anymail_setting('api_url', esp_name=esp_name, kwargs=kwargs,
|
||||||
default="https://api.mailgun.net/v3")
|
default="https://api.mailgun.net/v3")
|
||||||
if not api_url.endswith("/"):
|
if not api_url.endswith("/"):
|
||||||
@@ -54,7 +56,7 @@ class MailgunPayload(RequestsPayload):
|
|||||||
|
|
||||||
def __init__(self, message, defaults, backend, *args, **kwargs):
|
def __init__(self, message, defaults, backend, *args, **kwargs):
|
||||||
auth = ("api", backend.api_key)
|
auth = ("api", backend.api_key)
|
||||||
self.sender_domain = None
|
self.sender_domain = backend.sender_domain
|
||||||
self.all_recipients = [] # used for backend.parse_recipient_status
|
self.all_recipients = [] # used for backend.parse_recipient_status
|
||||||
|
|
||||||
# late-binding of recipient-variables:
|
# late-binding of recipient-variables:
|
||||||
|
|||||||
@@ -41,6 +41,20 @@ root of the settings file if neither ``ANYMAIL["MAILGUN_API_KEY"]``
|
|||||||
nor ``ANYMAIL_MAILGUN_API_KEY`` is set.
|
nor ``ANYMAIL_MAILGUN_API_KEY`` is set.
|
||||||
|
|
||||||
|
|
||||||
|
.. setting:: ANYMAIL_MAILGUN_SENDER_DOMAIN
|
||||||
|
|
||||||
|
.. rubric:: MAILGUN_SENDER_DOMAIN
|
||||||
|
|
||||||
|
If you are using a specific `Mailgun sender domain`_
|
||||||
|
that is *different* from your messages' `from_email` domains,
|
||||||
|
set this to the domain you've configured in your Mailgun account.
|
||||||
|
|
||||||
|
If your messages' `from_email` domains always match a configured
|
||||||
|
Mailgun sender domain, this setting is not needed.
|
||||||
|
|
||||||
|
See :ref:`mailgun-sender-domain` below for examples.
|
||||||
|
|
||||||
|
|
||||||
.. setting:: ANYMAIL_MAILGUN_API_URL
|
.. setting:: ANYMAIL_MAILGUN_API_URL
|
||||||
|
|
||||||
.. rubric:: MAILGUN_API_URL
|
.. rubric:: MAILGUN_API_URL
|
||||||
@@ -58,32 +72,40 @@ The default is ``MAILGUN_API_URL = "https://api.mailgun.net/v3"``
|
|||||||
Email sender domain
|
Email sender domain
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
Mailgun's API requires a sender domain `in the API url <base-url>`_.
|
Mailgun's API requires identifying the sender domain.
|
||||||
By default, Anymail will use the domain of each email's from address
|
By default, Anymail uses the domain of each messages's `from_email`
|
||||||
as the domain for the Mailgun API.
|
(e.g., "example.com" for "from\@example.com").
|
||||||
|
|
||||||
If you need to override this default, you can use Anymail's
|
You will need to override this default if you are using
|
||||||
:attr:`esp_extra` dict, either on an individual message:
|
a dedicated `Mailgun sender domain`_ that is different from
|
||||||
|
a message's `from_email` domain.
|
||||||
.. code-block:: python
|
|
||||||
|
For example, if you are sending from "orders\@example.com", but your
|
||||||
message = EmailMessage(from_email="sales@europe.example.com", ...)
|
Mailgun account is configured for "*mail1*.example.com", you should provide
|
||||||
message.esp_extra = {"sender_domain": "example.com"}
|
:setting:`MAILGUN_SENDER_DOMAIN <ANYMAIL_MAILGUN_SENDER_DOMAIN>` in your settings.py:
|
||||||
|
|
||||||
|
|
||||||
... or as a global :ref:`send default <send-defaults>` setting that applies
|
|
||||||
to all messages:
|
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
:emphasize-lines: 4
|
||||||
|
|
||||||
ANYMAIL = {
|
ANYMAIL = {
|
||||||
...
|
...
|
||||||
"MAILGUN_SEND_DEFAULTS": {
|
"MAILGUN_API_KEY": "<your API key>",
|
||||||
"esp_extra": {"sender_domain": "example.com"}
|
"MAILGUN_SENDER_DOMAIN": "mail1.example.com"
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.. _base-url: https://documentation.mailgun.com/api-intro.html#base-url
|
|
||||||
|
If you need to override the sender domain for an individual message,
|
||||||
|
include `sender_domain` in Anymail's :attr:`~anymail.message.AnymailMessage.esp_extra`
|
||||||
|
for that message:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
message = EmailMessage(from_email="marketing@example.com", ...)
|
||||||
|
message.esp_extra = {"sender_domain": "mail2.example.com"}
|
||||||
|
|
||||||
|
|
||||||
|
.. _Mailgun sender domain:
|
||||||
|
https://help.mailgun.com/hc/en-us/articles/202256730-How-do-I-pick-a-domain-name-for-my-Mailgun-account-
|
||||||
|
|
||||||
|
|
||||||
.. _mailgun-esp-extra:
|
.. _mailgun-esp-extra:
|
||||||
|
|||||||
@@ -383,8 +383,8 @@ class MailgunBackendAnymailFeatureTests(MailgunBackendMockAPITestCase):
|
|||||||
|
|
||||||
def test_sender_domain(self):
|
def test_sender_domain(self):
|
||||||
"""Mailgun send domain can come from from_email or esp_extra"""
|
"""Mailgun send domain can come from from_email or esp_extra"""
|
||||||
# You could also use ANYMAIL_SEND_DEFAULTS={'esp_extra': {'sender_domain': 'your-domain.com'}}
|
# You could also use MAILGUN_SENDER_DOMAIN in your ANYMAIL settings, as in the next test.
|
||||||
# (The mailgun_integration_tests do that.)
|
# (The mailgun_integration_tests also do that.)
|
||||||
self.message.from_email = "Test From <from@from-email.example.com>"
|
self.message.from_email = "Test From <from@from-email.example.com>"
|
||||||
self.message.send()
|
self.message.send()
|
||||||
self.assert_esp_called('/from-email.example.com/messages') # API url includes the sender-domain
|
self.assert_esp_called('/from-email.example.com/messages') # API url includes the sender-domain
|
||||||
@@ -393,6 +393,11 @@ class MailgunBackendAnymailFeatureTests(MailgunBackendMockAPITestCase):
|
|||||||
self.message.send()
|
self.message.send()
|
||||||
self.assert_esp_called('/esp-extra.example.com/messages') # overrides from_email
|
self.assert_esp_called('/esp-extra.example.com/messages') # overrides from_email
|
||||||
|
|
||||||
|
@override_settings(ANYMAIL_MAILGUN_SENDER_DOMAIN='mg.example.com')
|
||||||
|
def test_sender_domain_setting(self):
|
||||||
|
self.message.send()
|
||||||
|
self.assert_esp_called('/mg.example.com/messages') # setting overrides from_email
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
|
|||||||
@@ -23,10 +23,9 @@ MAILGUN_TEST_DOMAIN = os.getenv('MAILGUN_TEST_DOMAIN')
|
|||||||
@unittest.skipUnless(MAILGUN_TEST_API_KEY and MAILGUN_TEST_DOMAIN,
|
@unittest.skipUnless(MAILGUN_TEST_API_KEY and MAILGUN_TEST_DOMAIN,
|
||||||
"Set MAILGUN_TEST_API_KEY and MAILGUN_TEST_DOMAIN environment variables "
|
"Set MAILGUN_TEST_API_KEY and MAILGUN_TEST_DOMAIN environment variables "
|
||||||
"to run Mailgun integration tests")
|
"to run Mailgun integration tests")
|
||||||
@override_settings(ANYMAIL_MAILGUN_API_KEY=MAILGUN_TEST_API_KEY,
|
@override_settings(ANYMAIL={'MAILGUN_API_KEY': MAILGUN_TEST_API_KEY,
|
||||||
ANYMAIL_MAILGUN_SEND_DEFAULTS={
|
'MAILGUN_SENDER_DOMAIN': MAILGUN_TEST_DOMAIN,
|
||||||
'esp_extra': {'o:testmode': 'yes',
|
'MAILGUN_SEND_DEFAULTS': {'esp_extra': {'o:testmode': 'yes'}}},
|
||||||
'sender_domain': MAILGUN_TEST_DOMAIN}},
|
|
||||||
EMAIL_BACKEND="anymail.backends.mailgun.MailgunBackend")
|
EMAIL_BACKEND="anymail.backends.mailgun.MailgunBackend")
|
||||||
class MailgunBackendIntegrationTests(SimpleTestCase, AnymailTestMixin):
|
class MailgunBackendIntegrationTests(SimpleTestCase, AnymailTestMixin):
|
||||||
"""Mailgun API integration tests
|
"""Mailgun API integration tests
|
||||||
@@ -168,7 +167,9 @@ class MailgunBackendIntegrationTests(SimpleTestCase, AnymailTestMixin):
|
|||||||
self.assertEqual(err.status_code, 400)
|
self.assertEqual(err.status_code, 400)
|
||||||
self.assertIn("'from' parameter is not a valid address", str(err))
|
self.assertIn("'from' parameter is not a valid address", str(err))
|
||||||
|
|
||||||
@override_settings(ANYMAIL_MAILGUN_API_KEY="Hey, that's not an API key!")
|
@override_settings(ANYMAIL={'MAILGUN_API_KEY': "Hey, that's not an API key",
|
||||||
|
'MAILGUN_SENDER_DOMAIN': MAILGUN_TEST_DOMAIN,
|
||||||
|
'MAILGUN_SEND_DEFAULTS': {'esp_extra': {'o:testmode': 'yes'}}})
|
||||||
def test_invalid_api_key(self):
|
def test_invalid_api_key(self):
|
||||||
with self.assertRaises(AnymailAPIError) as cm:
|
with self.assertRaises(AnymailAPIError) as cm:
|
||||||
self.message.send()
|
self.message.send()
|
||||||
|
|||||||
Reference in New Issue
Block a user