1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
|
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()
|