Files
django-anymail/tests/test_mandrill_integration.py
Mike Edmunds 4f4461af4d Tests: update Mandrill integration
Mandrill has changed status code for
invalid from_email from 500 to 400.
(We don't actually care about the specific
code, just that the error is caught and
reported.)
2023-06-27 12:23:35 -07:00

176 lines
7.4 KiB
Python

import os
import unittest
from email.utils import formataddr
from django.core import mail
from django.test import SimpleTestCase, override_settings, tag
from anymail.exceptions import AnymailAPIError, AnymailRecipientsRefused
from anymail.message import AnymailMessage
from .utils import AnymailTestMixin, sample_image_path
ANYMAIL_TEST_MANDRILL_API_KEY = os.getenv("ANYMAIL_TEST_MANDRILL_API_KEY")
ANYMAIL_TEST_MANDRILL_DOMAIN = os.getenv("ANYMAIL_TEST_MANDRILL_DOMAIN")
@tag("mandrill", "live")
@unittest.skipUnless(
ANYMAIL_TEST_MANDRILL_API_KEY and ANYMAIL_TEST_MANDRILL_DOMAIN,
"Set ANYMAIL_TEST_MANDRILL_API_KEY and ANYMAIL_TEST_MANDRILL_DOMAIN "
"environment variables to run integration tests",
)
@override_settings(
MANDRILL_API_KEY=ANYMAIL_TEST_MANDRILL_API_KEY,
EMAIL_BACKEND="anymail.backends.mandrill.EmailBackend",
)
class MandrillBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
"""Mandrill API integration tests
These tests run against the **live** Mandrill API, using the
environment variable `ANYMAIL_TEST_MANDRILL_API_KEY` as the API key.
If that variable is not set, these tests won't run.
See https://mailchimp.com/developer/transactional/docs/fundamentals/#test-mode
for info on Mandrill test keys.
"""
def setUp(self):
super().setUp()
self.from_email = self.addr("from")
self.message = mail.EmailMultiAlternatives(
"Anymail Mandrill integration test",
"Text content",
self.from_email,
[self.addr("test+to1")],
)
self.message.attach_alternative("<p>HTML content</p>", "text/html")
def addr(self, username, display_name=None):
"""Construct test email address within our test domain"""
# Because integration tests run within a Mandrill trial account,
# both sender and recipient addresses must be within the test domain.
# (Other recipient addresses will be rejected with 'recipient-domain-mismatch'.)
email = "{username}@{domain}".format(
username=username, domain=ANYMAIL_TEST_MANDRILL_DOMAIN
)
if display_name is not None:
return formataddr((display_name, email))
else:
return email
def test_simple_send(self):
# Example of getting the Mandrill send status and _id from the message
sent_count = self.message.send()
self.assertEqual(sent_count, 1)
# noinspection PyUnresolvedReferences
anymail_status = self.message.anymail_status
to_email = self.message.to[0] # test+to1@{ANYMAIL_TEST_MANDRILL_DOMAIN}
sent_status = anymail_status.recipients[to_email].status
message_id = anymail_status.recipients[to_email].message_id
# successful send (could still bounce later):
self.assertIn(sent_status, ["sent", "queued"])
# don't know what it'll be, but it should exist:
self.assertGreater(len(message_id), 0)
# set of all recipient statuses:
self.assertEqual(anymail_status.status, {sent_status})
# because only a single recipient (else would be a set):
self.assertEqual(anymail_status.message_id, message_id)
def test_all_options(self):
message = AnymailMessage(
subject="Anymail Mandrill all-options integration test",
body="This is the text body",
from_email=self.addr("from", "Test From, with comma"),
to=[self.addr("test+to1"), self.addr("test+to2", "Recipient 2")],
cc=[self.addr("test+cc1"), self.addr("test+cc2", "Copy 2")],
bcc=[self.addr("test+bcc1"), self.addr("test+bcc2", "Blind Copy 2")],
reply_to=["reply1@example.com", "Reply 2 <reply2@example.com>"],
headers={"X-Anymail-Test": "value"},
# no metadata, send_at, track_clicks support
tags=["tag 1"], # max one tag
track_opens=True,
)
message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
message.attach("attachment2.csv", "ID,Name\n1,Amy Lina", "text/csv")
cid = message.attach_inline_image_file(sample_image_path())
message.attach_alternative(
"<p><b>HTML:</b> with <a href='http://example.com'>link</a>"
"and image: <img src='cid:%s'></div>" % cid,
"text/html",
)
message.send()
self.assertTrue(message.anymail_status.status.issubset({"queued", "sent"}))
def test_invalid_from(self):
# Example of trying to send from an invalid address
self.message.from_email = (
"webmaster@localhost" # Django default DEFAULT_FROM_EMAIL
)
with self.assertRaisesMessage(AnymailAPIError, "email address is invalid"):
self.message.send()
def test_invalid_to(self):
# Example of detecting when a recipient is not a valid email address
self.message.to = ["invalid@localhost"]
try:
self.message.send()
except AnymailRecipientsRefused:
# Mandrill refused to deliver the mail -- message.anymail_status
# will tell you why:
# noinspection PyUnresolvedReferences
anymail_status = self.message.anymail_status
self.assertEqual(
anymail_status.recipients["invalid@localhost"].status, "invalid"
)
self.assertEqual(anymail_status.status, {"invalid"})
else:
# Sometimes Mandrill queues these test sends
# noinspection PyUnresolvedReferences
if self.message.anymail_status.status == {"queued"}:
self.skipTest("Mandrill queued the send -- can't complete this test")
else:
self.fail(
"Anymail did not raise AnymailRecipientsRefused"
" for invalid recipient"
)
def test_rejected_to(self):
# Example of detecting when a recipient is on Mandrill's rejection blacklist
self.message.to = ["reject@test.mandrillapp.com"]
try:
self.message.send()
except AnymailRecipientsRefused:
# Mandrill refused to deliver the mail -- message.anymail_status will
# tell you why:
# noinspection PyUnresolvedReferences
anymail_status = self.message.anymail_status
self.assertEqual(
anymail_status.recipients["reject@test.mandrillapp.com"].status,
"rejected",
)
self.assertEqual(anymail_status.status, {"rejected"})
else:
# Sometimes Mandrill queues these test sends
# noinspection PyUnresolvedReferences
if self.message.anymail_status.status == {"queued"}:
self.skipTest("Mandrill queued the send -- can't complete this test")
else:
self.fail(
"Anymail did not raise AnymailRecipientsRefused"
" for blacklist recipient"
)
@override_settings(MANDRILL_API_KEY="Hey, that's not an API key!")
def test_invalid_api_key(self):
# Example of trying to send with an invalid MANDRILL_API_KEY.
# Mandrill responds either 401 or 500 status for this case (it varies),
# but always seems to include the message "Invalid API key".
# Either response should result in an AnymailAPIError.
with self.assertRaisesMessage(AnymailAPIError, "Invalid API key"):
self.message.send()