File: test_mailersend_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 (189 lines) | stat: -rw-r--r-- 8,373 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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
import os
import unittest
from datetime import datetime, timedelta
from email.utils import formataddr

from django.test import SimpleTestCase, override_settings, tag

from anymail.exceptions import AnymailAPIError
from anymail.message import AnymailMessage

from .utils import AnymailTestMixin, sample_image_path

ANYMAIL_TEST_MAILERSEND_API_TOKEN = os.getenv("ANYMAIL_TEST_MAILERSEND_API_TOKEN")
ANYMAIL_TEST_MAILERSEND_DOMAIN = os.getenv("ANYMAIL_TEST_MAILERSEND_DOMAIN")


@tag("mailersend", "live")
@unittest.skipUnless(
    ANYMAIL_TEST_MAILERSEND_API_TOKEN and ANYMAIL_TEST_MAILERSEND_DOMAIN,
    "Set ANYMAIL_TEST_MAILERSEND_API_TOKEN and ANYMAIL_TEST_MAILERSEND_DOMAIN"
    " environment variables to run MailerSend integration tests",
)
@override_settings(
    ANYMAIL={
        "MAILERSEND_API_TOKEN": ANYMAIL_TEST_MAILERSEND_API_TOKEN,
    },
    EMAIL_BACKEND="anymail.backends.mailersend.EmailBackend",
)
class MailerSendBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
    """MailerSend API integration tests

    These tests run against the **live** MailerSend API, using the
    environment variable `ANYMAIL_TEST_MAILERSEND_API_TOKEN` as the API token
    and `ANYMAIL_TEST_MAILERSEND_DOMAIN` as the sender domain.
    If those variables are not set, these tests won't run.

    """

    def setUp(self):
        super().setUp()
        self.from_email = f"from@{ANYMAIL_TEST_MAILERSEND_DOMAIN}"
        self.message = AnymailMessage(
            "Anymail MailerSend integration test",
            "Text content",
            self.from_email,
            ["test+to1@anymail.dev"],
        )
        self.message.attach_alternative("<p>HTML content</p>", "text/html")

    def test_simple_send(self):
        # Example of getting the MailerSend send status and message id from the message
        sent_count = self.message.send()
        self.assertEqual(sent_count, 1)

        anymail_status = self.message.anymail_status
        sent_status = anymail_status.recipients["test+to1@anymail.dev"].status
        message_id = anymail_status.recipients["test+to1@anymail.dev"].message_id

        self.assertEqual(sent_status, "queued")  # MailerSend queues
        # don't know what it'll be, but it should exist (and not be a bulk id):
        self.assertGreater(len(message_id), 0)
        self.assertFalse(message_id.startswith("bulk:"))

        # set of all recipient statuses:
        self.assertEqual(anymail_status.status, {sent_status})
        self.assertEqual(anymail_status.message_id, message_id)

    def test_all_options(self):
        send_at = datetime.now() + timedelta(minutes=2)
        from_email = formataddr(("Test From, with comma", self.from_email))
        message = AnymailMessage(
            subject="Anymail MailerSend all-options integration test",
            body="This is the text body",
            from_email=from_email,
            to=[
                "test+to1@anymail.dev",
                "Recipient 2 <test+to2@anymail.dev>",
                "test+bounce@anymail.dev",  # will be rejected
            ],
            cc=["test+cc1@anymail.dev", "Copy 2 <test+cc2@anymail.dev>"],
            bcc=["test+bcc1@anymail.dev", "Blind Copy 2 <test+bcc2@anymail.dev>"],
            # MailerSend only supports single reply_to:
            reply_to=["Reply <reply@example.com>"],
            headers={
                # Special handling for these headers (available to all accounts):
                "Precedence": "bulk",
                "In-Reply-To": "earlier-id@anymail.dev",
                # Only "enterprise accounts" can send other custom headers:
                "X-Custom": "anymail test",
            },
            send_at=send_at,
            tags=["tag 1", "tag 2"],
            track_clicks=False,
            track_opens=True,
        )
        message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
        message.attach("vedhæftet fil.csv", "ID,Name\n1,3", "text/csv")
        cid = message.attach_inline_image_file(
            sample_image_path(), domain=ANYMAIL_TEST_MAILERSEND_DOMAIN
        )
        message.attach_alternative(
            f"<div>This is the <i>html</i> body <img src='cid:{cid}'></div>",
            "text/html",
        )

        message.send()

        # First two recipients should be queued, other should be bounced
        self.assertEqual(message.anymail_status.status, {"queued", "rejected"})
        recipient_status = message.anymail_status.recipients
        self.assertEqual(recipient_status["test+to1@anymail.dev"].status, "queued")
        self.assertEqual(recipient_status["test+to2@anymail.dev"].status, "queued")
        self.assertEqual(recipient_status["test+bounce@anymail.dev"].status, "rejected")

    def test_stored_template(self):
        message = AnymailMessage(
            # id of a real template named in Anymail's MailerSend test account:
            template_id="vywj2lpokkm47oqz",
            to=[
                "test+to1@anymail.dev",
                "test+to2@anymail.dev",
                "test+bounce@anymail.dev",  # will be rejected
            ],
            merge_data={
                "test+to1@anymail.dev": {"name": "First Recipient", "order": 12345},
                "test+to2@anymail.dev": {"name": "Second Recipient", "order": 67890},
                "test+bounce@anymail.dev": {"name": "Bounces", "order": 3},
            },
            merge_global_data={"date": "yesterday"},
            esp_extra={
                # CAREFUL: with "expose-to-list", all recipients will see
                #   every other recipient's email address. (See docs!)
                "batch_send_mode": "expose-to-list"
            },
        )
        message.from_email = None  # use template From
        message.send()
        recipient_status = message.anymail_status.recipients
        self.assertEqual(recipient_status["test+to1@anymail.dev"].status, "queued")
        self.assertEqual(recipient_status["test+to2@anymail.dev"].status, "queued")
        self.assertEqual(recipient_status["test+bounce@anymail.dev"].status, "rejected")
        self.assertFalse(
            recipient_status["test+to1@anymail.dev"].message_id.startswith("bulk:")
        )
        self.assertIsNone(recipient_status["test+bounce@anymail.dev"].message_id)

    def test_batch_send_mode_bulk(self):
        # Same test as above, but with batch_send_mode "use-bulk-email".
        # (Uses different API; status is handled very differently.)
        message = AnymailMessage(
            # id of a real template named in Anymail's MailerSend test account:
            template_id="vywj2lpokkm47oqz",
            to=[
                "test+to1@anymail.dev",
                "test+to2@anymail.dev",
                "test+bounce@anymail.dev",  # will be rejected
            ],
            merge_data={
                "test+to1@anymail.dev": {"name": "First Recipient", "order": 12345},
                "test+to2@anymail.dev": {"name": "Second Recipient", "order": 67890},
                "test+bounce@anymail.dev": {"name": "Bounces", "order": 3},
            },
            merge_global_data={"date": "yesterday"},
            esp_extra={"batch_send_mode": "use-bulk-email"},
        )
        message.from_email = None  # use template From
        message.send()
        recipient_status = message.anymail_status.recipients
        # With use-bulk-email, must poll bulk-email status API to determine status:
        self.assertEqual(recipient_status["test+to1@anymail.dev"].status, "unknown")
        self.assertEqual(recipient_status["test+to2@anymail.dev"].status, "unknown")
        self.assertEqual(recipient_status["test+bounce@anymail.dev"].status, "unknown")
        # With use-bulk-email, message_id will be MailerSend's bulk_email_id
        # rather than an actual message_id. Anymail adds "bulk:" to differentiate:
        self.assertTrue(
            recipient_status["test+to1@anymail.dev"].message_id.startswith("bulk:")
        )
        self.assertTrue(
            recipient_status["test+bounce@anymail.dev"].message_id.startswith("bulk:")
        )

    @override_settings(
        ANYMAIL={
            "MAILERSEND_API_TOKEN": "Hey, that's not an API token",
        }
    )
    def test_invalid_api_key(self):
        with self.assertRaisesMessage(AnymailAPIError, "Unauthenticated"):
            self.message.send()