File: test_mandrill_integration.py

package info (click to toggle)
django-anymail 13.0-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 2,480 kB
  • sloc: python: 27,832; makefile: 132; javascript: 33; sh: 9
file content (175 lines) | stat: -rw-r--r-- 7,581 bytes parent folder | download | duplicates (2)
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()