CI/Docs: move to anymail.dev

Move all integration tests and contact emails to anymail.dev. 
(Stop using anymail.info.)
This commit is contained in:
Mike Edmunds
2022-02-02 13:59:09 -08:00
committed by GitHub
parent 4d93183e5e
commit 5fdc285e82
13 changed files with 161 additions and 130 deletions

View File

@@ -71,16 +71,22 @@ jobs:
TOX_FORCE_IGNORE_OUTCOME: false TOX_FORCE_IGNORE_OUTCOME: false
ANYMAIL_RUN_LIVE_TESTS: true ANYMAIL_RUN_LIVE_TESTS: true
ANYMAIL_TEST_AMAZON_SES_ACCESS_KEY_ID: ${{ secrets.ANYMAIL_TEST_AMAZON_SES_ACCESS_KEY_ID }} ANYMAIL_TEST_AMAZON_SES_ACCESS_KEY_ID: ${{ secrets.ANYMAIL_TEST_AMAZON_SES_ACCESS_KEY_ID }}
ANYMAIL_TEST_AMAZON_SES_DOMAIN: ${{ secrets.ANYMAIL_TEST_AMAZON_SES_DOMAIN }}
ANYMAIL_TEST_AMAZON_SES_REGION_NAME: ${{ secrets.ANYMAIL_TEST_AMAZON_SES_REGION_NAME }} ANYMAIL_TEST_AMAZON_SES_REGION_NAME: ${{ secrets.ANYMAIL_TEST_AMAZON_SES_REGION_NAME }}
ANYMAIL_TEST_AMAZON_SES_SECRET_ACCESS_KEY: ${{ secrets.ANYMAIL_TEST_AMAZON_SES_SECRET_ACCESS_KEY }} ANYMAIL_TEST_AMAZON_SES_SECRET_ACCESS_KEY: ${{ secrets.ANYMAIL_TEST_AMAZON_SES_SECRET_ACCESS_KEY }}
ANYMAIL_TEST_MAILGUN_API_KEY: ${{ secrets.ANYMAIL_TEST_MAILGUN_API_KEY }} ANYMAIL_TEST_MAILGUN_API_KEY: ${{ secrets.ANYMAIL_TEST_MAILGUN_API_KEY }}
ANYMAIL_TEST_MAILGUN_DOMAIN: ${{ secrets.ANYMAIL_TEST_MAILGUN_DOMAIN }} ANYMAIL_TEST_MAILGUN_DOMAIN: ${{ secrets.ANYMAIL_TEST_MAILGUN_DOMAIN }}
ANYMAIL_TEST_MAILJET_API_KEY: ${{ secrets.ANYMAIL_TEST_MAILJET_API_KEY }} ANYMAIL_TEST_MAILJET_API_KEY: ${{ secrets.ANYMAIL_TEST_MAILJET_API_KEY }}
ANYMAIL_TEST_MAILJET_DOMAIN: ${{ secrets.ANYMAIL_TEST_MAILJET_DOMAIN }}
ANYMAIL_TEST_MAILJET_SECRET_KEY: ${{ secrets.ANYMAIL_TEST_MAILJET_SECRET_KEY }} ANYMAIL_TEST_MAILJET_SECRET_KEY: ${{ secrets.ANYMAIL_TEST_MAILJET_SECRET_KEY }}
ANYMAIL_TEST_MANDRILL_API_KEY: ${{ secrets.ANYMAIL_TEST_MANDRILL_API_KEY }} ANYMAIL_TEST_MANDRILL_API_KEY: ${{ secrets.ANYMAIL_TEST_MANDRILL_API_KEY }}
ANYMAIL_TEST_POSTMARK_DOMAIN: ${{ secrets.ANYMAIL_TEST_POSTMARK_DOMAIN }}
ANYMAIL_TEST_POSTMARK_SERVER_TOKEN: ${{ secrets.ANYMAIL_TEST_POSTMARK_SERVER_TOKEN }} ANYMAIL_TEST_POSTMARK_SERVER_TOKEN: ${{ secrets.ANYMAIL_TEST_POSTMARK_SERVER_TOKEN }}
ANYMAIL_TEST_POSTMARK_TEMPLATE_ID: ${{ secrets.ANYMAIL_TEST_POSTMARK_TEMPLATE_ID }} ANYMAIL_TEST_POSTMARK_TEMPLATE_ID: ${{ secrets.ANYMAIL_TEST_POSTMARK_TEMPLATE_ID }}
ANYMAIL_TEST_SENDGRID_API_KEY: ${{ secrets.ANYMAIL_TEST_SENDGRID_API_KEY }} ANYMAIL_TEST_SENDGRID_API_KEY: ${{ secrets.ANYMAIL_TEST_SENDGRID_API_KEY }}
ANYMAIL_TEST_SENDGRID_DOMAIN: ${{ secrets.ANYMAIL_TEST_SENDGRID_DOMAIN }}
ANYMAIL_TEST_SENDGRID_TEMPLATE_ID: ${{ secrets.ANYMAIL_TEST_SENDGRID_TEMPLATE_ID }} ANYMAIL_TEST_SENDGRID_TEMPLATE_ID: ${{ secrets.ANYMAIL_TEST_SENDGRID_TEMPLATE_ID }}
ANYMAIL_TEST_SENDINBLUE_API_KEY: ${{ secrets.ANYMAIL_TEST_SENDINBLUE_API_KEY }} ANYMAIL_TEST_SENDINBLUE_API_KEY: ${{ secrets.ANYMAIL_TEST_SENDINBLUE_API_KEY }}
ANYMAIL_TEST_SENDINBLUE_DOMAIN: ${{ secrets.ANYMAIL_TEST_SENDINBLUE_DOMAIN }}
ANYMAIL_TEST_SPARKPOST_API_KEY: ${{ secrets.ANYMAIL_TEST_SPARKPOST_API_KEY }} ANYMAIL_TEST_SPARKPOST_API_KEY: ${{ secrets.ANYMAIL_TEST_SPARKPOST_API_KEY }}
ANYMAIL_TEST_SPARKPOST_DOMAIN: ${{ secrets.ANYMAIL_TEST_SPARKPOST_DOMAIN }}

View File

@@ -38,7 +38,7 @@ Bugs
You can report problems or request features in `Anymail's GitHub issue tracker`_. You can report problems or request features in `Anymail's GitHub issue tracker`_.
(For a security-related issue that should not be disclosed publicly, instead email (For a security-related issue that should not be disclosed publicly, instead email
Anymail's maintainers at security<AT>anymail<DOT>info.) Anymail's maintainers at *security\<at>anymail\<dot>dev*.)
We also have some :ref:`troubleshooting` information that may be helpful. We also have some :ref:`troubleshooting` information that may be helpful.

View File

@@ -37,7 +37,7 @@ analytics tracking, see the "Information for Visitors of Sites and Apps Using
Google Analytics" section of Google's `Safeguarding your data`_ document. Google Analytics" section of Google's `Safeguarding your data`_ document.
Questions about privacy and information practices related to this Anymail Questions about privacy and information practices related to this Anymail
documentation site can be emailed to *privacy\<at>anymail\<dot>info*. documentation site can be emailed to *privacy\<at>anymail\<dot>dev*.
(This is not an appropriate contact for questions about *using* Anymail; (This is not an appropriate contact for questions about *using* Anymail;
see :ref:`help` if you need assistance with your code.) see :ref:`help` if you need assistance with your code.)

View File

@@ -55,7 +55,7 @@ Here's how to contact the Anymail community:
**"I found a security issue!"** **"I found a security issue!"**
Contact the Anymail maintainers by emailing *security<AT>anymail<DOT>info.* Contact the Anymail maintainers by emailing *security\<at>anymail\<dot>dev.*
(Please don't open a GitHub issue or post publicly about potential security problems.) (Please don't open a GitHub issue or post publicly about potential security problems.)
**"Could Anymail support this ESP or feature...?"** **"Could Anymail support this ESP or feature...?"**

View File

@@ -1,6 +1,7 @@
import os import os
import unittest import unittest
import warnings import warnings
from email.utils import formataddr
from django.test import SimpleTestCase, override_settings, tag from django.test import SimpleTestCase, override_settings, tag
@@ -13,11 +14,15 @@ from .utils import AnymailTestMixin, sample_image_path
ANYMAIL_TEST_AMAZON_SES_ACCESS_KEY_ID = os.getenv("ANYMAIL_TEST_AMAZON_SES_ACCESS_KEY_ID") ANYMAIL_TEST_AMAZON_SES_ACCESS_KEY_ID = os.getenv("ANYMAIL_TEST_AMAZON_SES_ACCESS_KEY_ID")
ANYMAIL_TEST_AMAZON_SES_SECRET_ACCESS_KEY = os.getenv("ANYMAIL_TEST_AMAZON_SES_SECRET_ACCESS_KEY") ANYMAIL_TEST_AMAZON_SES_SECRET_ACCESS_KEY = os.getenv("ANYMAIL_TEST_AMAZON_SES_SECRET_ACCESS_KEY")
ANYMAIL_TEST_AMAZON_SES_REGION_NAME = os.getenv("ANYMAIL_TEST_AMAZON_SES_REGION_NAME", "us-east-1") ANYMAIL_TEST_AMAZON_SES_REGION_NAME = os.getenv("ANYMAIL_TEST_AMAZON_SES_REGION_NAME", "us-east-1")
ANYMAIL_TEST_AMAZON_SES_DOMAIN = os.getenv("ANYMAIL_TEST_AMAZON_SES_DOMAIN")
@unittest.skipUnless(ANYMAIL_TEST_AMAZON_SES_ACCESS_KEY_ID and ANYMAIL_TEST_AMAZON_SES_SECRET_ACCESS_KEY, @unittest.skipUnless(
ANYMAIL_TEST_AMAZON_SES_ACCESS_KEY_ID
and ANYMAIL_TEST_AMAZON_SES_SECRET_ACCESS_KEY
and ANYMAIL_TEST_AMAZON_SES_DOMAIN,
"Set ANYMAIL_TEST_AMAZON_SES_ACCESS_KEY_ID and ANYMAIL_TEST_AMAZON_SES_SECRET_ACCESS_KEY " "Set ANYMAIL_TEST_AMAZON_SES_ACCESS_KEY_ID and ANYMAIL_TEST_AMAZON_SES_SECRET_ACCESS_KEY "
"environment variables to run Amazon SES integration tests") "and ANYMAIL_TEST_AMAZON_SES_DOMAIN environment variables to run Amazon SES integration tests")
@override_settings( @override_settings(
EMAIL_BACKEND="anymail.backends.amazon_ses.EmailBackend", EMAIL_BACKEND="anymail.backends.amazon_ses.EmailBackend",
ANYMAIL={ ANYMAIL={
@@ -47,17 +52,13 @@ class AmazonSESBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
To avoid stacking up a pile of undeliverable @example.com To avoid stacking up a pile of undeliverable @example.com
emails, the tests use Amazon's @simulator.amazonses.com addresses. emails, the tests use Amazon's @simulator.amazonses.com addresses.
https://docs.aws.amazon.com/ses/latest/DeveloperGuide/mailbox-simulator.html https://docs.aws.amazon.com/ses/latest/DeveloperGuide/mailbox-simulator.html
Amazon SES also doesn't support arbitrary senders (so no from@example.com).
We've set up @test-ses.anymail.info as a validated sending domain for these tests.
You may need to change the from_email to your own address when testing.
""" """
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.from_email = 'test@%s' % ANYMAIL_TEST_AMAZON_SES_DOMAIN
self.message = AnymailMessage('Anymail Amazon SES integration test', 'Text content', self.message = AnymailMessage('Anymail Amazon SES integration test', 'Text content',
'test@test-ses.anymail.info', ['success@simulator.amazonses.com']) self.from_email, ['success@simulator.amazonses.com'])
self.message.attach_alternative('<p>HTML content</p>', "text/html") self.message.attach_alternative('<p>HTML content</p>', "text/html")
# boto3 relies on GC to close connections. Python 3 warns about unclosed ssl.SSLSocket during cleanup. # boto3 relies on GC to close connections. Python 3 warns about unclosed ssl.SSLSocket during cleanup.
@@ -85,7 +86,7 @@ class AmazonSESBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
message = AnymailMessage( message = AnymailMessage(
subject="Anymail Amazon SES all-options integration test", subject="Anymail Amazon SES all-options integration test",
body="This is the text body", body="This is the text body",
from_email='"Test From" <test@test-ses.anymail.info>', from_email=formataddr(("Test From, with comma", self.from_email)),
to=["success+to1@simulator.amazonses.com", "Recipient 2 <success+to2@simulator.amazonses.com>"], to=["success+to1@simulator.amazonses.com", "Recipient 2 <success+to2@simulator.amazonses.com>"],
cc=["success+cc1@simulator.amazonses.com", "Copy 2 <success+cc2@simulator.amazonses.com>"], cc=["success+cc1@simulator.amazonses.com", "Copy 2 <success+cc2@simulator.amazonses.com>"],
bcc=["success+bcc1@simulator.amazonses.com", "Blind Copy 2 <success+bcc2@simulator.amazonses.com>"], bcc=["success+bcc1@simulator.amazonses.com", "Blind Copy 2 <success+bcc2@simulator.amazonses.com>"],
@@ -119,7 +120,7 @@ class AmazonSESBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
# }) # })
message = AnymailMessage( message = AnymailMessage(
template_id='TestTemplate', template_id='TestTemplate',
from_email='"Test From" <test@test-ses.anymail.info>', from_email=formataddr(("Test From", self.from_email)),
to=["First Recipient <success+to1@simulator.amazonses.com>", to=["First Recipient <success+to1@simulator.amazonses.com>",
"success+to2@simulator.amazonses.com"], "success+to2@simulator.amazonses.com"],
merge_data={ merge_data={

View File

@@ -2,6 +2,7 @@ import logging
import os import os
import unittest import unittest
from datetime import datetime, timedelta from datetime import datetime, timedelta
from email.utils import formataddr
from time import sleep from time import sleep
import requests import requests
@@ -36,8 +37,9 @@ class MailgunBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.from_email = 'from@%s' % ANYMAIL_TEST_MAILGUN_DOMAIN
self.message = AnymailMessage('Anymail Mailgun integration test', 'Text content', self.message = AnymailMessage('Anymail Mailgun integration test', 'Text content',
'from@example.com', ['test+to1@anymail.info']) self.from_email, ['test+to1@anymail.dev'])
self.message.attach_alternative('<p>HTML content</p>', "text/html") self.message.attach_alternative('<p>HTML content</p>', "text/html")
def fetch_mailgun_events(self, message_id, event=None, def fetch_mailgun_events(self, message_id, event=None,
@@ -86,8 +88,8 @@ class MailgunBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
self.assertEqual(sent_count, 1) self.assertEqual(sent_count, 1)
anymail_status = self.message.anymail_status anymail_status = self.message.anymail_status
sent_status = anymail_status.recipients['test+to1@anymail.info'].status sent_status = anymail_status.recipients['test+to1@anymail.dev'].status
message_id = anymail_status.recipients['test+to1@anymail.info'].message_id message_id = anymail_status.recipients['test+to1@anymail.dev'].message_id
self.assertEqual(sent_status, 'queued') # Mailgun always queues self.assertEqual(sent_status, 'queued') # Mailgun always queues
self.assertGreater(len(message_id), 0) # don't know what it'll be, but it should exist self.assertGreater(len(message_id), 0) # don't know what it'll be, but it should exist
@@ -98,13 +100,14 @@ class MailgunBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
def test_all_options(self): def test_all_options(self):
send_at = datetime.now().replace(microsecond=0) + timedelta(minutes=2) send_at = datetime.now().replace(microsecond=0) + timedelta(minutes=2)
send_at_timestamp = send_at.timestamp() send_at_timestamp = send_at.timestamp()
from_email = formataddr(("Test From, with comma", self.from_email))
message = AnymailMessage( message = AnymailMessage(
subject="Anymail Mailgun all-options integration test", subject="Anymail Mailgun all-options integration test",
body="This is the text body", body="This is the text body",
from_email="Test From <from@example.com>, also-from@example.com", from_email=from_email,
to=["test+to1@anymail.info", "Recipient 2 <test+to2@anymail.info>"], to=["test+to1@anymail.dev", "Recipient 2 <test+to2@anymail.dev>"],
cc=["test+cc1@anymail.info", "Copy 2 <test+cc2@anymail.info>"], cc=["test+cc1@anymail.dev", "Copy 2 <test+cc2@anymail.dev>"],
bcc=["test+bcc1@anymail.info", "Blind Copy 2 <test+bcc2@anymail.info>"], bcc=["test+bcc1@anymail.dev", "Blind Copy 2 <test+bcc2@anymail.dev>"],
reply_to=["reply1@example.com", "Reply 2 <reply2@example.com>"], reply_to=["reply1@example.com", "Reply 2 <reply2@example.com>"],
headers={"X-Anymail-Test": "value"}, headers={"X-Anymail-Test": "value"},
@@ -136,14 +139,14 @@ class MailgunBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
{"meta1": "simple string", "meta2": "2"}) # all metadata values become strings {"meta1": "simple string", "meta2": "2"}) # all metadata values become strings
self.assertEqual(event["message"]["scheduled-for"], send_at_timestamp) self.assertEqual(event["message"]["scheduled-for"], send_at_timestamp)
self.assertIn(event["recipient"], ['test+to1@anymail.info', 'test+to2@anymail.info', self.assertIn(event["recipient"], ['test+to1@anymail.dev', 'test+to2@anymail.dev',
'test+cc1@anymail.info', 'test+cc2@anymail.info', 'test+cc1@anymail.dev', 'test+cc2@anymail.dev',
'test+bcc1@anymail.info', 'test+bcc2@anymail.info']) 'test+bcc1@anymail.dev', 'test+bcc2@anymail.dev'])
headers = event["message"]["headers"] headers = event["message"]["headers"]
self.assertEqual(headers["from"], "Test From <from@example.com>, also-from@example.com") self.assertEqual(headers["from"], from_email)
self.assertEqual(headers["to"], self.assertEqual(headers["to"],
"test+to1@anymail.info, Recipient 2 <test+to2@anymail.info>") "test+to1@anymail.dev, Recipient 2 <test+to2@anymail.dev>")
self.assertEqual(headers["subject"], "Anymail Mailgun all-options integration test") self.assertEqual(headers["subject"], "Anymail Mailgun all-options integration test")
attachments = event["message"]["attachments"] attachments = event["message"]["attachments"]
@@ -167,12 +170,12 @@ class MailgunBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
message = AnymailMessage( message = AnymailMessage(
template_id='test-template', # name of a real template named in Anymail's Mailgun test account template_id='test-template', # name of a real template named in Anymail's Mailgun test account
subject='Your order %recipient.order%', # Mailgun templates don't define subject subject='Your order %recipient.order%', # Mailgun templates don't define subject
from_email='Test From <from@example.com>', # Mailgun templates don't define sender from_email=formataddr(('Test From>', self.from_email)), # Mailgun templates don't define sender
to=["test+to1@anymail.info"], to=["test+to1@anymail.dev"],
# metadata and merge_data must not have any conflicting keys when using template_id # metadata and merge_data must not have any conflicting keys when using template_id
metadata={"meta1": "simple string", "meta2": 2}, metadata={"meta1": "simple string", "meta2": 2},
merge_data={ merge_data={
'test+to1@anymail.info': { 'test+to1@anymail.dev': {
'name': "Test Recipient", 'name': "Test Recipient",
} }
}, },
@@ -182,7 +185,7 @@ class MailgunBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
) )
message.send() message.send()
recipient_status = message.anymail_status.recipients recipient_status = message.anymail_status.recipients
self.assertEqual(recipient_status['test+to1@anymail.info'].status, 'queued') self.assertEqual(recipient_status['test+to1@anymail.dev'].status, 'queued')
# As of Anymail 0.10, this test is no longer possible, because # As of Anymail 0.10, this test is no longer possible, because
# Anymail now raises AnymailInvalidAddress without even calling Mailgun # Anymail now raises AnymailInvalidAddress without even calling Mailgun

View File

@@ -1,5 +1,6 @@
import os import os
import unittest import unittest
from email.utils import formataddr
from django.test import SimpleTestCase, override_settings, tag from django.test import SimpleTestCase, override_settings, tag
@@ -10,11 +11,13 @@ from .utils import AnymailTestMixin, sample_image_path
ANYMAIL_TEST_MAILJET_API_KEY = os.getenv('ANYMAIL_TEST_MAILJET_API_KEY') ANYMAIL_TEST_MAILJET_API_KEY = os.getenv('ANYMAIL_TEST_MAILJET_API_KEY')
ANYMAIL_TEST_MAILJET_SECRET_KEY = os.getenv('ANYMAIL_TEST_MAILJET_SECRET_KEY') ANYMAIL_TEST_MAILJET_SECRET_KEY = os.getenv('ANYMAIL_TEST_MAILJET_SECRET_KEY')
ANYMAIL_TEST_MAILJET_DOMAIN = os.getenv('ANYMAIL_TEST_MAILJET_DOMAIN')
@tag('mailjet', 'live') @tag('mailjet', 'live')
@unittest.skipUnless(ANYMAIL_TEST_MAILJET_API_KEY and ANYMAIL_TEST_MAILJET_SECRET_KEY, @unittest.skipUnless(
"Set ANYMAIL_TEST_MAILJET_API_KEY and ANYMAIL_TEST_MAILJET_SECRET_KEY " ANYMAIL_TEST_MAILJET_API_KEY and ANYMAIL_TEST_MAILJET_SECRET_KEY and ANYMAIL_TEST_MAILJET_DOMAIN,
"Set ANYMAIL_TEST_MAILJET_API_KEY and ANYMAIL_TEST_MAILJET_SECRET_KEY and ANYMAIL_TEST_MAILJET_DOMAIN "
"environment variables to run Mailjet integration tests") "environment variables to run Mailjet integration tests")
@override_settings(ANYMAIL={"MAILJET_API_KEY": ANYMAIL_TEST_MAILJET_API_KEY, @override_settings(ANYMAIL={"MAILJET_API_KEY": ANYMAIL_TEST_MAILJET_API_KEY,
"MAILJET_SECRET_KEY": ANYMAIL_TEST_MAILJET_SECRET_KEY, "MAILJET_SECRET_KEY": ANYMAIL_TEST_MAILJET_SECRET_KEY,
@@ -26,20 +29,18 @@ class MailjetBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
These tests run against the **live** Mailjet API, using the These tests run against the **live** Mailjet API, using the
environment variables `ANYMAIL_TEST_MAILJET_API_KEY` and `ANYMAIL_TEST_MAILJET_SECRET_KEY` environment variables `ANYMAIL_TEST_MAILJET_API_KEY` and `ANYMAIL_TEST_MAILJET_SECRET_KEY`
as the API key and API secret key, respectively. as the API key and API secret key, respectively, and `ANYMAIL_TEST_MAILJET_DOMAIN` as
If those variables are not set, these tests won't run. a validated Mailjet sending domain. If those variables are not set, these tests won't run.
These tests enable Mailjet's SandboxMode to avoid sending any email; These tests enable Mailjet's SandboxMode to avoid sending any email;
remove the esp_extra setting above if you are trying to actually send test messages. remove the esp_extra setting above if you are trying to actually send test messages.
Mailjet also doesn't support unverified senders (so no from@example.com).
We've set up @test-mj.anymail.info as a validated sending domain for these tests.
""" """
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.from_email = 'test@%s' % ANYMAIL_TEST_MAILJET_DOMAIN
self.message = AnymailMessage('Anymail Mailjet integration test', 'Text content', self.message = AnymailMessage('Anymail Mailjet integration test', 'Text content',
'test@test-mj.anymail.info', ['test+to1@anymail.info']) self.from_email, ['test+to1@anymail.dev'])
self.message.attach_alternative('<p>HTML content</p>', "text/html") self.message.attach_alternative('<p>HTML content</p>', "text/html")
def test_simple_send(self): def test_simple_send(self):
@@ -48,8 +49,8 @@ class MailjetBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
self.assertEqual(sent_count, 1) self.assertEqual(sent_count, 1)
anymail_status = self.message.anymail_status anymail_status = self.message.anymail_status
sent_status = anymail_status.recipients['test+to1@anymail.info'].status sent_status = anymail_status.recipients['test+to1@anymail.dev'].status
message_id = anymail_status.recipients['test+to1@anymail.info'].message_id message_id = anymail_status.recipients['test+to1@anymail.dev'].message_id
self.assertEqual(sent_status, 'sent') self.assertEqual(sent_status, 'sent')
self.assertRegex(message_id, r'.+') self.assertRegex(message_id, r'.+')
@@ -60,10 +61,10 @@ class MailjetBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
message = AnymailMessage( message = AnymailMessage(
subject="Anymail Mailjet all-options integration test", subject="Anymail Mailjet all-options integration test",
body="This is the text body", body="This is the text body",
from_email='"Test Sender, Inc." <test@test-mj.anymail.info>', from_email=formataddr(("Test Sender, Inc.", self.from_email)),
to=['test+to1@anymail.info', '"Recipient, 2nd" <test+to2@anymail.info>'], to=['test+to1@anymail.dev', '"Recipient, 2nd" <test+to2@anymail.dev>'],
cc=['test+cc1@anymail.info', 'Copy 2 <test+cc1@anymail.info>'], cc=['test+cc1@anymail.dev', 'Copy 2 <test+cc1@anymail.dev>'],
bcc=['test+bcc1@anymail.info', 'Blind Copy 2 <test+bcc2@anymail.info>'], bcc=['test+bcc1@anymail.dev', 'Blind Copy 2 <test+bcc2@anymail.dev>'],
reply_to=['"Reply, To" <reply2@example.com>'], # Mailjet only supports single reply_to reply_to=['"Reply, To" <reply2@example.com>'], # Mailjet only supports single reply_to
headers={"X-Anymail-Test": "value"}, headers={"X-Anymail-Test": "value"},
@@ -88,11 +89,11 @@ class MailjetBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
subject="Anymail Mailjet merge_data test", # Mailjet doesn't support merge fields in the subject subject="Anymail Mailjet merge_data test", # Mailjet doesn't support merge fields in the subject
body="This body includes merge data: [[var:value]]\n" body="This body includes merge data: [[var:value]]\n"
"And global merge data: [[var:global]]", "And global merge data: [[var:global]]",
from_email="Test From <test@test-mj.anymail.info>", from_email=formataddr(("Test From", self.from_email)),
to=["test+to1@anymail.info", "Recipient 2 <test+to2@anymail.info>"], to=["test+to1@anymail.dev", "Recipient 2 <test+to2@anymail.dev>"],
merge_data={ merge_data={
'test+to1@anymail.info': {'value': 'one'}, 'test+to1@anymail.dev': {'value': 'one'},
'test+to2@anymail.info': {'value': 'two'}, 'test+to2@anymail.dev': {'value': 'two'},
}, },
merge_global_data={ merge_global_data={
'global': 'global_value' 'global': 'global_value'
@@ -100,15 +101,15 @@ class MailjetBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
) )
message.send() message.send()
recipient_status = message.anymail_status.recipients recipient_status = message.anymail_status.recipients
self.assertEqual(recipient_status['test+to1@anymail.info'].status, 'sent') self.assertEqual(recipient_status['test+to1@anymail.dev'].status, 'sent')
self.assertEqual(recipient_status['test+to2@anymail.info'].status, 'sent') self.assertEqual(recipient_status['test+to2@anymail.dev'].status, 'sent')
def test_stored_template(self): def test_stored_template(self):
message = AnymailMessage( message = AnymailMessage(
template_id='176375', # ID of the real template named 'test-template' in our Mailjet test account template_id='176375', # ID of the real template named 'test-template' in our Mailjet test account
to=["test+to1@anymail.info"], to=["test+to1@anymail.dev"],
merge_data={ merge_data={
'test+to1@anymail.info': { 'test+to1@anymail.dev': {
'name': "Test Recipient", 'name': "Test Recipient",
} }
}, },
@@ -119,7 +120,7 @@ class MailjetBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
message.from_email = None # use the template's sender email/name message.from_email = None # use the template's sender email/name
message.send() message.send()
recipient_status = message.anymail_status.recipients recipient_status = message.anymail_status.recipients
self.assertEqual(recipient_status['test+to1@anymail.info'].status, 'sent') self.assertEqual(recipient_status['test+to1@anymail.dev'].status, 'sent')
@override_settings(ANYMAIL={"MAILJET_API_KEY": "Hey, that's not an API key!", @override_settings(ANYMAIL={"MAILJET_API_KEY": "Hey, that's not an API key!",
"MAILJET_SECRET_KEY": "and this isn't the secret for it"}) "MAILJET_SECRET_KEY": "and this isn't the secret for it"})

View File

@@ -1,5 +1,6 @@
import os import os
import unittest import unittest
from email.utils import formataddr
from django.core import mail from django.core import mail
from django.test import SimpleTestCase, override_settings, tag from django.test import SimpleTestCase, override_settings, tag
@@ -10,11 +11,13 @@ from anymail.message import AnymailMessage
from .utils import AnymailTestMixin, sample_image_path from .utils import AnymailTestMixin, sample_image_path
ANYMAIL_TEST_MANDRILL_API_KEY = os.getenv('ANYMAIL_TEST_MANDRILL_API_KEY') 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') @tag('mandrill', 'live')
@unittest.skipUnless(ANYMAIL_TEST_MANDRILL_API_KEY, @unittest.skipUnless(ANYMAIL_TEST_MANDRILL_API_KEY and ANYMAIL_TEST_MANDRILL_DOMAIN,
"Set ANYMAIL_TEST_MANDRILL_API_KEY environment variable to run integration tests") "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, @override_settings(MANDRILL_API_KEY=ANYMAIL_TEST_MANDRILL_API_KEY,
EMAIL_BACKEND="anymail.backends.mandrill.EmailBackend") EMAIL_BACKEND="anymail.backends.mandrill.EmailBackend")
class MandrillBackendIntegrationTests(AnymailTestMixin, SimpleTestCase): class MandrillBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
@@ -26,13 +29,13 @@ class MandrillBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
See https://mandrill.zendesk.com/hc/en-us/articles/205582447 See https://mandrill.zendesk.com/hc/en-us/articles/205582447
for info on Mandrill test keys. for info on Mandrill test keys.
""" """
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.from_email = 'from@%s' % ANYMAIL_TEST_MANDRILL_DOMAIN
self.message = mail.EmailMultiAlternatives('Anymail Mandrill integration test', 'Text content', self.message = mail.EmailMultiAlternatives('Anymail Mandrill integration test', 'Text content',
'from@example.com', ['test+to1@anymail.info']) self.from_email, ['test+to1@anymail.dev'])
self.message.attach_alternative('<p>HTML content</p>', "text/html") self.message.attach_alternative('<p>HTML content</p>', "text/html")
def test_simple_send(self): def test_simple_send(self):
@@ -42,8 +45,8 @@ class MandrillBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
anymail_status = self.message.anymail_status anymail_status = self.message.anymail_status
sent_status = anymail_status.recipients['test+to1@anymail.info'].status sent_status = anymail_status.recipients['test+to1@anymail.dev'].status
message_id = anymail_status.recipients['test+to1@anymail.info'].message_id message_id = anymail_status.recipients['test+to1@anymail.dev'].message_id
self.assertIn(sent_status, ['sent', 'queued']) # successful send (could still bounce later) self.assertIn(sent_status, ['sent', 'queued']) # successful send (could still bounce later)
self.assertGreater(len(message_id), 0) # don't know what it'll be, but it should exist self.assertGreater(len(message_id), 0) # don't know what it'll be, but it should exist
@@ -55,10 +58,10 @@ class MandrillBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
message = AnymailMessage( message = AnymailMessage(
subject="Anymail Mandrill all-options integration test", subject="Anymail Mandrill all-options integration test",
body="This is the text body", body="This is the text body",
from_email="Test From <from@example.com>", from_email=formataddr(("Test From, with comma", self.from_email)),
to=["test+to1@anymail.info", "Recipient 2 <test+to2@anymail.info>"], to=["test+to1@anymail.dev", "Recipient 2 <test+to2@anymail.dev>"],
cc=["test+cc1@anymail.info", "Copy 2 <test+cc2@anymail.info>"], cc=["test+cc1@anymail.dev", "Copy 2 <test+cc2@anymail.dev>"],
bcc=["test+bcc1@anymail.info", "Blind Copy 2 <test+bcc2@anymail.info>"], bcc=["test+bcc1@anymail.dev", "Blind Copy 2 <test+bcc2@anymail.dev>"],
reply_to=["reply1@example.com", "Reply 2 <reply2@example.com>"], reply_to=["reply1@example.com", "Reply 2 <reply2@example.com>"],
headers={"X-Anymail-Test": "value"}, headers={"X-Anymail-Test": "value"},

View File

@@ -1,5 +1,6 @@
import os import os
import unittest import unittest
from email.utils import formataddr
from django.test import SimpleTestCase, override_settings, tag from django.test import SimpleTestCase, override_settings, tag
@@ -11,11 +12,13 @@ from .utils import AnymailTestMixin
ANYMAIL_TEST_POSTAL_API_KEY = os.getenv('ANYMAIL_TEST_POSTAL_API_KEY') ANYMAIL_TEST_POSTAL_API_KEY = os.getenv('ANYMAIL_TEST_POSTAL_API_KEY')
ANYMAIL_TEST_POSTAL_API_URL = os.getenv('ANYMAIL_TEST_POSTAL_API_URL') ANYMAIL_TEST_POSTAL_API_URL = os.getenv('ANYMAIL_TEST_POSTAL_API_URL')
ANYMAIL_TEST_POSTAL_DOMAIN = os.getenv('ANYMAIL_TEST_POSTAL_DOMAIN')
@tag('postal', 'live') @tag('postal', 'live')
@unittest.skipUnless(ANYMAIL_TEST_POSTAL_API_KEY and ANYMAIL_TEST_POSTAL_API_URL, @unittest.skipUnless(
"Set ANYMAIL_TEST_POSTAL_API_KEY and ANYMAIL_TEST_POSTAL_API_URL " ANYMAIL_TEST_POSTAL_API_KEY and ANYMAIL_TEST_POSTAL_API_URL and ANYMAIL_TEST_POSTAL_DOMAIN,
"Set ANYMAIL_TEST_POSTAL_API_KEY and ANYMAIL_TEST_POSTAL_API_URL and ANYMAIL_TEST_POSTAL_DOMAIN "
"environment variables to run Postal integration tests") "environment variables to run Postal integration tests")
@override_settings(ANYMAIL_POSTAL_API_KEY=ANYMAIL_TEST_POSTAL_API_KEY, @override_settings(ANYMAIL_POSTAL_API_KEY=ANYMAIL_TEST_POSTAL_API_KEY,
ANYMAIL_POSTAL_API_URL=ANYMAIL_TEST_POSTAL_API_URL, ANYMAIL_POSTAL_API_URL=ANYMAIL_TEST_POSTAL_API_URL,
@@ -31,8 +34,9 @@ class PostalBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.from_email = 'from@%s' % ANYMAIL_TEST_POSTAL_DOMAIN
self.message = AnymailMessage('Anymail Postal integration test', 'Text content', self.message = AnymailMessage('Anymail Postal integration test', 'Text content',
'from@example.com', ['test+to1@anymail.info']) self.from_email, ['test+to1@anymail.dev'])
self.message.attach_alternative('<p>HTML content</p>', "text/html") self.message.attach_alternative('<p>HTML content</p>', "text/html")
def test_simple_send(self): def test_simple_send(self):
@@ -41,8 +45,8 @@ class PostalBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
self.assertEqual(sent_count, 1) self.assertEqual(sent_count, 1)
anymail_status = self.message.anymail_status anymail_status = self.message.anymail_status
sent_status = anymail_status.recipients['test+to1@anymail.info'].status sent_status = anymail_status.recipients['test+to1@anymail.dev'].status
message_id = anymail_status.recipients['test+to1@anymail.info'].message_id message_id = anymail_status.recipients['test+to1@anymail.dev'].message_id
self.assertEqual(sent_status, 'queued') self.assertEqual(sent_status, 'queued')
self.assertGreater(len(message_id), 0) # non-empty string self.assertGreater(len(message_id), 0) # non-empty string
@@ -53,11 +57,11 @@ class PostalBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
message = AnymailMessage( message = AnymailMessage(
subject="Anymail Postal all-options integration test", subject="Anymail Postal all-options integration test",
body="This is the text body", body="This is the text body",
from_email="Test From <from@example.com>", from_email=formataddr(("Test From, with comma", self.from_email)),
envelope_sender="bounces@example.com", envelope_sender="bounces@%s" % ANYMAIL_TEST_POSTAL_DOMAIN,
to=["test+to1@anymail.info", "Recipient 2 <test+to2@anymail.info>"], to=["test+to1@anymail.dev", "Recipient 2 <test+to2@anymail.dev>"],
cc=["test+cc1@anymail.info", "Copy 2 <test+cc2@anymail.info>"], cc=["test+cc1@anymail.dev", "Copy 2 <test+cc2@anymail.dev>"],
bcc=["test+bcc1@anymail.info", "Blind Copy 2 <test+bcc2@anymail.info>"], bcc=["test+bcc1@anymail.dev", "Blind Copy 2 <test+bcc2@anymail.dev>"],
reply_to=["reply1@example.com"], reply_to=["reply1@example.com"],
headers={"X-Anymail-Test": "value"}, headers={"X-Anymail-Test": "value"},
tags=["tag 1"], # max one tag tags=["tag 1"], # max one tag
@@ -67,11 +71,11 @@ class PostalBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
message.send() message.send()
self.assertEqual(message.anymail_status.status, {'queued'}) self.assertEqual(message.anymail_status.status, {'queued'})
self.assertEqual(message.anymail_status.recipients['test+to1@anymail.info'].status, 'queued') self.assertEqual(message.anymail_status.recipients['test+to1@anymail.dev'].status, 'queued')
self.assertEqual(message.anymail_status.recipients['test+to2@anymail.info'].status, 'queued') self.assertEqual(message.anymail_status.recipients['test+to2@anymail.dev'].status, 'queued')
# distinct messages should have different message_ids: # distinct messages should have different message_ids:
self.assertNotEqual(message.anymail_status.recipients['test+to1@anymail.info'].message_id, self.assertNotEqual(message.anymail_status.recipients['test+to1@anymail.dev'].message_id,
message.anymail_status.recipients['teset+to2@anymail.info'].message_id) message.anymail_status.recipients['teset+to2@anymail.dev'].message_id)
def test_invalid_from(self): def test_invalid_from(self):
self.message.from_email = 'webmaster@localhost' # Django's default From self.message.from_email = 'webmaster@localhost' # Django's default From

View File

@@ -1,5 +1,6 @@
import os import os
import unittest import unittest
from email.utils import formataddr
from django.test import SimpleTestCase, override_settings, tag from django.test import SimpleTestCase, override_settings, tag
@@ -13,9 +14,13 @@ from .utils import AnymailTestMixin, sample_image_path
# But to test template sends, a real Postmark server token and template id are needed: # But to test template sends, a real Postmark server token and template id are needed:
ANYMAIL_TEST_POSTMARK_SERVER_TOKEN = os.getenv('ANYMAIL_TEST_POSTMARK_SERVER_TOKEN') ANYMAIL_TEST_POSTMARK_SERVER_TOKEN = os.getenv('ANYMAIL_TEST_POSTMARK_SERVER_TOKEN')
ANYMAIL_TEST_POSTMARK_TEMPLATE_ID = os.getenv('ANYMAIL_TEST_POSTMARK_TEMPLATE_ID') ANYMAIL_TEST_POSTMARK_TEMPLATE_ID = os.getenv('ANYMAIL_TEST_POSTMARK_TEMPLATE_ID')
ANYMAIL_TEST_POSTMARK_DOMAIN = os.getenv('ANYMAIL_TEST_POSTMARK_DOMAIN')
@tag('postmark', 'live') @tag('postmark', 'live')
@unittest.skipUnless(ANYMAIL_TEST_POSTMARK_DOMAIN,
"Set ANYMAIL_TEST_POSTMARK_DOMAIN environment variable "
"to run Postmark template integration tests")
@override_settings(ANYMAIL_POSTMARK_SERVER_TOKEN="POSTMARK_API_TEST", @override_settings(ANYMAIL_POSTMARK_SERVER_TOKEN="POSTMARK_API_TEST",
EMAIL_BACKEND="anymail.backends.postmark.EmailBackend") EMAIL_BACKEND="anymail.backends.postmark.EmailBackend")
class PostmarkBackendIntegrationTests(AnymailTestMixin, SimpleTestCase): class PostmarkBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
@@ -27,8 +32,9 @@ class PostmarkBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.from_email = 'from@%s' % ANYMAIL_TEST_POSTMARK_DOMAIN
self.message = AnymailMessage('Anymail Postmark integration test', 'Text content', self.message = AnymailMessage('Anymail Postmark integration test', 'Text content',
'from@example.com', ['test+to1@anymail.info']) self.from_email, ['test+to1@anymail.dev'])
self.message.attach_alternative('<p>HTML content</p>', "text/html") self.message.attach_alternative('<p>HTML content</p>', "text/html")
def test_simple_send(self): def test_simple_send(self):
@@ -37,8 +43,8 @@ class PostmarkBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
self.assertEqual(sent_count, 1) self.assertEqual(sent_count, 1)
anymail_status = self.message.anymail_status anymail_status = self.message.anymail_status
sent_status = anymail_status.recipients['test+to1@anymail.info'].status sent_status = anymail_status.recipients['test+to1@anymail.dev'].status
message_id = anymail_status.recipients['test+to1@anymail.info'].message_id message_id = anymail_status.recipients['test+to1@anymail.dev'].message_id
self.assertEqual(sent_status, 'sent') self.assertEqual(sent_status, 'sent')
self.assertGreater(len(message_id), 0) # non-empty string self.assertGreater(len(message_id), 0) # non-empty string
@@ -49,11 +55,10 @@ class PostmarkBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
message = AnymailMessage( message = AnymailMessage(
subject="Anymail Postmark all-options integration test", subject="Anymail Postmark all-options integration test",
body="This is the text body", body="This is the text body",
# Postmark accepts multiple from_email addresses, but truncates to the first on their end from_email=formataddr(("Test From, with comma", self.from_email)),
from_email="Test From <from@example.com>, also-from@example.com", to=["test+to1@anymail.dev", "Recipient 2 <test+to2@anymail.dev>"],
to=["test+to1@anymail.info", "Recipient 2 <test+to2@anymail.info>"], cc=["test+cc1@anymail.dev", "Copy 2 <test+cc2@anymail.dev>"],
cc=["test+cc1@anymail.info", "Copy 2 <test+cc2@anymail.info>"], bcc=["test+bcc1@anymail.dev", "Blind Copy 2 <test+bcc2@anymail.dev>"],
bcc=["test+bcc1@anymail.info", "Blind Copy 2 <test+bcc2@anymail.info>"],
reply_to=["reply1@example.com", "Reply 2 <reply2@example.com>"], reply_to=["reply1@example.com", "Reply 2 <reply2@example.com>"],
headers={"X-Anymail-Test": "value"}, headers={"X-Anymail-Test": "value"},
@@ -74,11 +79,11 @@ class PostmarkBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
message.send() message.send()
self.assertEqual(message.anymail_status.status, {'sent'}) self.assertEqual(message.anymail_status.status, {'sent'})
self.assertEqual(message.anymail_status.recipients['test+to1@anymail.info'].status, 'sent') self.assertEqual(message.anymail_status.recipients['test+to1@anymail.dev'].status, 'sent')
self.assertEqual(message.anymail_status.recipients['test+to2@anymail.info'].status, 'sent') self.assertEqual(message.anymail_status.recipients['test+to2@anymail.dev'].status, 'sent')
# distinct messages should have different message_ids: # distinct messages should have different message_ids:
self.assertNotEqual(message.anymail_status.recipients['test+to1@anymail.info'].message_id, self.assertNotEqual(message.anymail_status.recipients['test+to1@anymail.dev'].message_id,
message.anymail_status.recipients['test+to2@anymail.info'].message_id) message.anymail_status.recipients['test+to2@anymail.dev'].message_id)
def test_invalid_from(self): def test_invalid_from(self):
self.message.from_email = 'webmaster@localhost' # Django's default From self.message.from_email = 'webmaster@localhost' # Django's default From
@@ -88,18 +93,21 @@ class PostmarkBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
self.assertEqual(err.status_code, 422) self.assertEqual(err.status_code, 422)
self.assertIn("Invalid 'From' address", str(err)) self.assertIn("Invalid 'From' address", str(err))
@unittest.skipUnless(ANYMAIL_TEST_POSTMARK_SERVER_TOKEN and ANYMAIL_TEST_POSTMARK_TEMPLATE_ID, @unittest.skipUnless(
ANYMAIL_TEST_POSTMARK_SERVER_TOKEN
and ANYMAIL_TEST_POSTMARK_TEMPLATE_ID
and ANYMAIL_TEST_POSTMARK_DOMAIN,
"Set ANYMAIL_TEST_POSTMARK_SERVER_TOKEN and ANYMAIL_TEST_POSTMARK_TEMPLATE_ID " "Set ANYMAIL_TEST_POSTMARK_SERVER_TOKEN and ANYMAIL_TEST_POSTMARK_TEMPLATE_ID "
"environment variables to run Postmark template integration tests") "and ANYMAIL_TEST_POSTMARK_DOMAIN environment variables to run Postmark template integration tests")
@override_settings(ANYMAIL_POSTMARK_SERVER_TOKEN=ANYMAIL_TEST_POSTMARK_SERVER_TOKEN) @override_settings(ANYMAIL_POSTMARK_SERVER_TOKEN=ANYMAIL_TEST_POSTMARK_SERVER_TOKEN)
def test_template(self): def test_template(self):
message = AnymailMessage( message = AnymailMessage(
from_email="from@test-pm.anymail.info", from_email=self.from_email,
to=["test+to1@anymail.info", "Second Recipient <test+to2@anymail.info>"], to=["test+to1@anymail.dev", "Second Recipient <test+to2@anymail.dev>"],
template_id=ANYMAIL_TEST_POSTMARK_TEMPLATE_ID, template_id=ANYMAIL_TEST_POSTMARK_TEMPLATE_ID,
merge_data={ merge_data={
"test+to1@anymail.info": {"name": "Recipient 1", "order_no": "12345"}, "test+to1@anymail.dev": {"name": "Recipient 1", "order_no": "12345"},
"test+to2@anymail.info": {"order_no": "6789"}, "test+to2@anymail.dev": {"order_no": "6789"},
}, },
merge_global_data={"name": "Valued Customer"}, merge_global_data={"name": "Valued Customer"},
) )

View File

@@ -1,6 +1,7 @@
import os import os
import unittest import unittest
from datetime import datetime, timedelta from datetime import datetime, timedelta
from email.utils import formataddr
from django.test import SimpleTestCase, override_settings, tag from django.test import SimpleTestCase, override_settings, tag
@@ -11,12 +12,13 @@ from .utils import AnymailTestMixin, sample_image_path
ANYMAIL_TEST_SENDGRID_API_KEY = os.getenv('ANYMAIL_TEST_SENDGRID_API_KEY') ANYMAIL_TEST_SENDGRID_API_KEY = os.getenv('ANYMAIL_TEST_SENDGRID_API_KEY')
ANYMAIL_TEST_SENDGRID_TEMPLATE_ID = os.getenv('ANYMAIL_TEST_SENDGRID_TEMPLATE_ID') ANYMAIL_TEST_SENDGRID_TEMPLATE_ID = os.getenv('ANYMAIL_TEST_SENDGRID_TEMPLATE_ID')
ANYMAIL_TEST_SENDGRID_DOMAIN = os.getenv('ANYMAIL_TEST_SENDGRID_DOMAIN')
@tag('sendgrid', 'live') @tag('sendgrid', 'live')
@unittest.skipUnless(ANYMAIL_TEST_SENDGRID_API_KEY, @unittest.skipUnless(ANYMAIL_TEST_SENDGRID_API_KEY and ANYMAIL_TEST_SENDGRID_DOMAIN,
"Set ANYMAIL_TEST_SENDGRID_API_KEY environment variable " "Set ANYMAIL_TEST_SENDGRID_API_KEY and ANYMAIL_TEST_SENDGRID_DOMAIN "
"to run SendGrid integration tests") "environment variables to run SendGrid integration tests")
@override_settings(ANYMAIL_SENDGRID_API_KEY=ANYMAIL_TEST_SENDGRID_API_KEY, @override_settings(ANYMAIL_SENDGRID_API_KEY=ANYMAIL_TEST_SENDGRID_API_KEY,
ANYMAIL_SENDGRID_SEND_DEFAULTS={"esp_extra": { ANYMAIL_SENDGRID_SEND_DEFAULTS={"esp_extra": {
"mail_settings": {"sandbox_mode": {"enable": True}}, "mail_settings": {"sandbox_mode": {"enable": True}},
@@ -34,13 +36,13 @@ class SendGridBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
The tests also use SendGrid's "sink domain" @sink.sendgrid.net for recipient addresses. The tests also use SendGrid's "sink domain" @sink.sendgrid.net for recipient addresses.
https://support.sendgrid.com/hc/en-us/articles/201995663-Safely-Test-Your-Sending-Speed https://support.sendgrid.com/hc/en-us/articles/201995663-Safely-Test-Your-Sending-Speed
""" """
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.from_email = 'from@%s' % ANYMAIL_TEST_SENDGRID_DOMAIN
self.message = AnymailMessage('Anymail SendGrid integration test', 'Text content', self.message = AnymailMessage('Anymail SendGrid integration test', 'Text content',
'from@example.com', ['to@sink.sendgrid.net']) self.from_email, ['to@sink.sendgrid.net'])
self.message.attach_alternative('<p>HTML content</p>', "text/html") self.message.attach_alternative('<p>HTML content</p>', "text/html")
def test_simple_send(self): def test_simple_send(self):
@@ -62,7 +64,7 @@ class SendGridBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
message = AnymailMessage( message = AnymailMessage(
subject="Anymail all-options integration test", subject="Anymail all-options integration test",
body="This is the text body", body="This is the text body",
from_email='"Test From, with comma" <from@example.com>', from_email=formataddr(("Test From, with comma", self.from_email)),
to=["to1@sink.sendgrid.net", '"Recipient 2, OK?" <to2@sink.sendgrid.net>'], to=["to1@sink.sendgrid.net", '"Recipient 2, OK?" <to2@sink.sendgrid.net>'],
cc=["cc1@sink.sendgrid.net", "Copy 2 <cc2@sink.sendgrid.net>"], cc=["cc1@sink.sendgrid.net", "Copy 2 <cc2@sink.sendgrid.net>"],
bcc=["bcc1@sink.sendgrid.net", "Blind Copy 2 <bcc2@sink.sendgrid.net>"], bcc=["bcc1@sink.sendgrid.net", "Blind Copy 2 <bcc2@sink.sendgrid.net>"],
@@ -91,7 +93,7 @@ class SendGridBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
message = AnymailMessage( message = AnymailMessage(
subject="Anymail merge_data test: %field%", subject="Anymail merge_data test: %field%",
body="This body includes merge data: %field%", body="This body includes merge data: %field%",
from_email="Test From <from@example.com>", from_email=formataddr(("Test From", self.from_email)),
to=["to1@sink.sendgrid.net", "Recipient 2 <to2@sink.sendgrid.net>"], to=["to1@sink.sendgrid.net", "Recipient 2 <to2@sink.sendgrid.net>"],
reply_to=['"Merge data in reply name: %field%" <reply@example.com>'], reply_to=['"Merge data in reply name: %field%" <reply@example.com>'],
merge_data={ merge_data={
@@ -112,7 +114,7 @@ class SendGridBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
"to a template in your SendGrid account to test stored templates") "to a template in your SendGrid account to test stored templates")
def test_stored_template(self): def test_stored_template(self):
message = AnymailMessage( message = AnymailMessage(
from_email="Test From <from@example.com>", from_email=formataddr(("Test From", self.from_email)),
to=["to@sink.sendgrid.net"], to=["to@sink.sendgrid.net"],
# Anymail's live test template has merge fields "name", "order_no", and "dept"... # Anymail's live test template has merge fields "name", "order_no", and "dept"...
template_id=ANYMAIL_TEST_SENDGRID_TEMPLATE_ID, template_id=ANYMAIL_TEST_SENDGRID_TEMPLATE_ID,

View File

@@ -1,5 +1,6 @@
import os import os
import unittest import unittest
from email.utils import formataddr
from django.test import SimpleTestCase, override_settings, tag from django.test import SimpleTestCase, override_settings, tag
@@ -9,12 +10,13 @@ from anymail.message import AnymailMessage
from .utils import AnymailTestMixin from .utils import AnymailTestMixin
ANYMAIL_TEST_SENDINBLUE_API_KEY = os.getenv('ANYMAIL_TEST_SENDINBLUE_API_KEY') ANYMAIL_TEST_SENDINBLUE_API_KEY = os.getenv('ANYMAIL_TEST_SENDINBLUE_API_KEY')
ANYMAIL_TEST_SENDINBLUE_DOMAIN = os.getenv('ANYMAIL_TEST_SENDINBLUE_DOMAIN')
@tag('sendinblue', 'live') @tag('sendinblue', 'live')
@unittest.skipUnless(ANYMAIL_TEST_SENDINBLUE_API_KEY, @unittest.skipUnless(ANYMAIL_TEST_SENDINBLUE_API_KEY and ANYMAIL_TEST_SENDINBLUE_DOMAIN,
"Set ANYMAIL_TEST_SENDINBLUE_API_KEY environment variable " "Set ANYMAIL_TEST_SENDINBLUE_API_KEY and ANYMAIL_TEST_SENDINBLUE_DOMAIN "
"to run SendinBlue integration tests") "environment variables to run SendinBlue integration tests")
@override_settings(ANYMAIL_SENDINBLUE_API_KEY=ANYMAIL_TEST_SENDINBLUE_API_KEY, @override_settings(ANYMAIL_SENDINBLUE_API_KEY=ANYMAIL_TEST_SENDINBLUE_API_KEY,
ANYMAIL_SENDINBLUE_SEND_DEFAULTS=dict(), ANYMAIL_SENDINBLUE_SEND_DEFAULTS=dict(),
EMAIL_BACKEND="anymail.backends.sendinblue.EmailBackend") EMAIL_BACKEND="anymail.backends.sendinblue.EmailBackend")
@@ -23,7 +25,8 @@ class SendinBlueBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
SendinBlue doesn't have sandbox so these tests run SendinBlue doesn't have sandbox so these tests run
against the **live** SendinBlue API, using the against the **live** SendinBlue API, using the
environment variable `ANYMAIL_TEST_SENDINBLUE_API_KEY` as the API key environment variable `ANYMAIL_TEST_SENDINBLUE_API_KEY` as the API key,
and `ANYMAIL_TEST_SENDINBLUE_DOMAIN` to construct sender addresses.
If those variables are not set, these tests won't run. If those variables are not set, these tests won't run.
https://developers.sendinblue.com/docs/faq#section-how-can-i-test-the-api- https://developers.sendinblue.com/docs/faq#section-how-can-i-test-the-api-
@@ -32,9 +35,9 @@ class SendinBlueBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.from_email = 'from@%s' % ANYMAIL_TEST_SENDINBLUE_DOMAIN
self.message = AnymailMessage('Anymail SendinBlue integration test', 'Text content', self.message = AnymailMessage('Anymail SendinBlue integration test', 'Text content',
'from@test-sb.anymail.info', ['test+to1@anymail.info']) self.from_email, ['test+to1@anymail.dev'])
self.message.attach_alternative('<p>HTML content</p>', "text/html") self.message.attach_alternative('<p>HTML content</p>', "text/html")
def test_simple_send(self): def test_simple_send(self):
@@ -43,8 +46,8 @@ class SendinBlueBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
self.assertEqual(sent_count, 1) self.assertEqual(sent_count, 1)
anymail_status = self.message.anymail_status anymail_status = self.message.anymail_status
sent_status = anymail_status.recipients['test+to1@anymail.info'].status sent_status = anymail_status.recipients['test+to1@anymail.dev'].status
message_id = anymail_status.recipients['test+to1@anymail.info'].message_id message_id = anymail_status.recipients['test+to1@anymail.dev'].message_id
self.assertEqual(sent_status, 'queued') # SendinBlue always queues self.assertEqual(sent_status, 'queued') # SendinBlue always queues
self.assertRegex(message_id, r'\<.+@.+\>') # Message-ID can be ...@smtp-relay.mail.fr or .sendinblue.com self.assertRegex(message_id, r'\<.+@.+\>') # Message-ID can be ...@smtp-relay.mail.fr or .sendinblue.com
@@ -55,10 +58,10 @@ class SendinBlueBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
message = AnymailMessage( message = AnymailMessage(
subject="Anymail SendinBlue all-options integration test", subject="Anymail SendinBlue all-options integration test",
body="This is the text body", body="This is the text body",
from_email='"Test From, with comma" <from@test-sb.anymail.info>', from_email=formataddr(("Test From, with comma", self.from_email)),
to=["test+to1@anymail.info", '"Recipient 2, OK?" <test+to2@anymail.info>'], to=["test+to1@anymail.dev", '"Recipient 2, OK?" <test+to2@anymail.dev>'],
cc=["test+cc1@anymail.info", "Copy 2 <test+cc2@anymail.info>"], cc=["test+cc1@anymail.dev", "Copy 2 <test+cc2@anymail.dev>"],
bcc=["test+bcc1@anymail.info", "Blind Copy 2 <test+bcc2@anymail.info>"], bcc=["test+bcc1@anymail.dev", "Blind Copy 2 <test+bcc2@anymail.dev>"],
reply_to=['"Reply, with comma" <reply@example.com>'], # SendinBlue API v3 only supports single reply-to reply_to=['"Reply, with comma" <reply@example.com>'], # SendinBlue API v3 only supports single reply-to
headers={"X-Anymail-Test": "value", "X-Anymail-Count": 3}, headers={"X-Anymail-Test": "value", "X-Anymail-Count": 3},
@@ -77,9 +80,9 @@ class SendinBlueBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
def test_template(self): def test_template(self):
message = AnymailMessage( message = AnymailMessage(
template_id=5, # There is a *new-style* template with this id in the Anymail test account template_id=5, # There is a *new-style* template with this id in the Anymail test account
from_email='Sender <from@test-sb.anymail.info>', # Override template sender from_email=formataddr(('Sender', self.from_email)), # Override template sender
to=["Recipient <test+to1@anymail.info>"], # No batch send (so max one recipient suggested) to=["Recipient <test+to1@anymail.dev>"], # No batch send (so max one recipient suggested)
reply_to=["Do not reply <reply@example.com>"], reply_to=["Do not reply <reply@example.dev>"],
tags=["using-template"], tags=["using-template"],
headers={"X-Anymail-Test": "group: A, variation: C"}, headers={"X-Anymail-Test": "group: A, variation: C"},
merge_global_data={ merge_global_data={

View File

@@ -1,6 +1,7 @@
import os import os
import unittest import unittest
from datetime import datetime, timedelta from datetime import datetime, timedelta
from email.utils import formataddr
from django.test import SimpleTestCase, override_settings, tag from django.test import SimpleTestCase, override_settings, tag
@@ -10,12 +11,13 @@ from anymail.message import AnymailMessage
from .utils import AnymailTestMixin, sample_image_path from .utils import AnymailTestMixin, sample_image_path
ANYMAIL_TEST_SPARKPOST_API_KEY = os.getenv('ANYMAIL_TEST_SPARKPOST_API_KEY') ANYMAIL_TEST_SPARKPOST_API_KEY = os.getenv('ANYMAIL_TEST_SPARKPOST_API_KEY')
ANYMAIL_TEST_SPARKPOST_DOMAIN = os.getenv('ANYMAIL_TEST_SPARKPOST_DOMAIN')
@tag('sparkpost', 'live') @tag('sparkpost', 'live')
@unittest.skipUnless(ANYMAIL_TEST_SPARKPOST_API_KEY, @unittest.skipUnless(ANYMAIL_TEST_SPARKPOST_API_KEY and ANYMAIL_TEST_SPARKPOST_DOMAIN,
"Set ANYMAIL_TEST_SPARKPOST_API_KEY environment variable " "Set ANYMAIL_TEST_SPARKPOST_API_KEY and ANYMAIL_TEST_SPARKPOST_DOMAIN "
"to run SparkPost integration tests") "environment variables to run SparkPost integration tests")
@override_settings(ANYMAIL_SPARKPOST_API_KEY=ANYMAIL_TEST_SPARKPOST_API_KEY, @override_settings(ANYMAIL_SPARKPOST_API_KEY=ANYMAIL_TEST_SPARKPOST_API_KEY,
EMAIL_BACKEND="anymail.backends.sparkpost.EmailBackend") EMAIL_BACKEND="anymail.backends.sparkpost.EmailBackend")
class SparkPostBackendIntegrationTests(AnymailTestMixin, SimpleTestCase): class SparkPostBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
@@ -29,15 +31,13 @@ class SparkPostBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
you ask. To avoid stacking up a pile of undeliverable @example.com you ask. To avoid stacking up a pile of undeliverable @example.com
emails, the tests use SparkPost's "sink domain" @*.sink.sparkpostmail.com. emails, the tests use SparkPost's "sink domain" @*.sink.sparkpostmail.com.
https://www.sparkpost.com/docs/faq/using-sink-server/ https://www.sparkpost.com/docs/faq/using-sink-server/
SparkPost also doesn't support arbitrary senders (so no from@example.com).
We've set up @test-sp.anymail.info as a validated sending domain for these tests.
""" """
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.from_email = 'test@%s' % ANYMAIL_TEST_SPARKPOST_DOMAIN
self.message = AnymailMessage('Anymail SparkPost integration test', 'Text content', self.message = AnymailMessage('Anymail SparkPost integration test', 'Text content',
'test@test-sp.anymail.info', ['to@test.sink.sparkpostmail.com']) self.from_email, ['to@test.sink.sparkpostmail.com'])
self.message.attach_alternative('<p>HTML content</p>', "text/html") self.message.attach_alternative('<p>HTML content</p>', "text/html")
def test_simple_send(self): def test_simple_send(self):
@@ -59,7 +59,7 @@ class SparkPostBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
message = AnymailMessage( message = AnymailMessage(
subject="Anymail all-options integration test", subject="Anymail all-options integration test",
body="This is the text body", body="This is the text body",
from_email="Test From <test@test-sp.anymail.info>", from_email=formataddr(("Test From, with comma", self.from_email)),
to=["to1@test.sink.sparkpostmail.com", "Recipient 2 <to2@test.sink.sparkpostmail.com>"], to=["to1@test.sink.sparkpostmail.com", "Recipient 2 <to2@test.sink.sparkpostmail.com>"],
# Limit the live b/cc's to avoid running through our small monthly allowance: # Limit the live b/cc's to avoid running through our small monthly allowance:
# cc=["cc1@test.sink.sparkpostmail.com", "Copy 2 <cc2@test.sink.sparkpostmail.com>"], # cc=["cc1@test.sink.sparkpostmail.com", "Copy 2 <cc2@test.sink.sparkpostmail.com>"],
@@ -90,7 +90,7 @@ class SparkPostBackendIntegrationTests(AnymailTestMixin, SimpleTestCase):
subject="Anymail merge_data test: {{ value }}", subject="Anymail merge_data test: {{ value }}",
body="This body includes merge data: {{ value }}\n" body="This body includes merge data: {{ value }}\n"
"And global merge data: {{ global }}", "And global merge data: {{ global }}",
from_email="Test From <test@test-sp.anymail.info>", from_email=formataddr(("Test From", self.from_email)),
to=["to1@test.sink.sparkpostmail.com", "Recipient 2 <to2@test.sink.sparkpostmail.com>"], to=["to1@test.sink.sparkpostmail.com", "Recipient 2 <to2@test.sink.sparkpostmail.com>"],
merge_data={ merge_data={
'to1@test.sink.sparkpostmail.com': {'value': 'one'}, 'to1@test.sink.sparkpostmail.com': {'value': 'one'},