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
|
import os
import unittest
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
ANYMAIL_TEST_RESEND_API_KEY = os.getenv("ANYMAIL_TEST_RESEND_API_KEY")
ANYMAIL_TEST_RESEND_DOMAIN = os.getenv("ANYMAIL_TEST_RESEND_DOMAIN")
@tag("resend", "live")
@unittest.skipUnless(
ANYMAIL_TEST_RESEND_API_KEY and ANYMAIL_TEST_RESEND_DOMAIN,
"Set ANYMAIL_TEST_RESEND_API_KEY and ANYMAIL_TEST_RESEND_DOMAIN "
"environment variables to run Resend integration tests",
)
@override_settings(
ANYMAIL_RESEND_API_KEY=ANYMAIL_TEST_RESEND_API_KEY,
EMAIL_BACKEND="anymail.backends.resend.EmailBackend",
)
class ResendBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
"""Resend.com API integration tests
Resend doesn't have sandbox so these tests run
against the **live** Resend API, using the
environment variable `ANYMAIL_TEST_RESEND_API_KEY` as the API key,
and `ANYMAIL_TEST_RESEND_DOMAIN` to construct sender addresses.
If those variables are not set, these tests won't run.
"""
def setUp(self):
super().setUp()
self.from_email = "from@%s" % ANYMAIL_TEST_RESEND_DOMAIN
self.message = AnymailMessage(
"Anymail Resend 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 Resend 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") # Resend always queues
self.assertGreater(len(message_id), 0) # non-empty string
# 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):
message = AnymailMessage(
subject="Anymail Resend all-options integration test",
body="This is the text body",
# Verify workarounds for address formatting issues:
from_email=formataddr(("Test «Från», med komma", self.from_email)),
to=["test+to1@anymail.dev", '"Recipient 2, OK?" <test+to2@anymail.dev>'],
cc=["test+cc1@anymail.dev", "Copy 2 <test+cc2@anymail.dev>"],
bcc=["test+bcc1@anymail.dev", "Blind Copy 2 <test+bcc2@anymail.dev>"],
reply_to=['"Reply, with comma" <reply@example.com>', "reply2@example.com"],
headers={"X-Anymail-Test": "value", "X-Anymail-Count": 3},
metadata={"meta1": "simple string", "meta2": 2},
tags=["tag 1", "tag 2"],
# Resend supports send_at or attachments, but not both at once.
# send_at=datetime.now() + timedelta(minutes=2),
)
message.attach_alternative("<p>HTML content</p>", "text/html")
message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
message.attach("attachment2.csv", "ID,Name\n1,Amy Lina", "text/csv")
message.send()
# Resend always queues:
self.assertEqual(message.anymail_status.status, {"queued"})
self.assertGreater(
len(message.anymail_status.message_id), 0
) # non-empty string
def test_batch_send(self):
# merge_metadata, merge_headers, or merge_data will use batch send API
message = AnymailMessage(
subject="Anymail Resend batch sendintegration test",
body="This is the text body",
from_email=self.from_email,
to=["test+to1@anymail.dev", '"Recipient 2" <test+to2@anymail.dev>'],
metadata={"meta1": "simple string", "meta2": 2},
merge_metadata={
"test+to1@anymail.dev": {"meta3": "recipient 1"},
"test+to2@anymail.dev": {"meta3": "recipient 2"},
},
tags=["tag 1", "tag 2"],
headers={
"List-Unsubscribe-Post": "List-Unsubscribe=One-Click",
"List-Unsubscribe": "<mailto:unsubscribe@example.com>",
},
merge_headers={
"test+to1@anymail.dev": {
"List-Unsubscribe": "<https://example.com/a/>",
},
"test+to2@anymail.dev": {
"List-Unsubscribe": "<https://example.com/b/>",
},
},
)
message.attach_alternative("<p>HTML content</p>", "text/html")
# Resend does not support attachments in batch send (2024-11-21)
# message.attach("attachment1.txt", "Here is some\ntext for you", "text/plain")
message.send()
# Resend always queues:
self.assertEqual(message.anymail_status.status, {"queued"})
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.assertRegex(recipient_status["test+to1@anymail.dev"].message_id, r".+")
self.assertRegex(recipient_status["test+to2@anymail.dev"].message_id, r".+")
# Each recipient gets their own message_id:
self.assertNotEqual(
recipient_status["test+to1@anymail.dev"].message_id,
recipient_status["test+to2@anymail.dev"].message_id,
)
@unittest.skip("Resend has stopped responding to bad/missing API keys (12/2023)")
@override_settings(ANYMAIL_RESEND_API_KEY="Hey, that's not an API key!")
def test_invalid_api_key(self):
with self.assertRaisesMessage(AnymailAPIError, "API key is invalid"):
self.message.send()
|