From 771d4040dfdc0cef5698ec4d3d8aa13e2a025f2b Mon Sep 17 00:00:00 2001 From: Charlie DeTar Date: Sun, 28 Jan 2018 13:25:05 -0700 Subject: [PATCH] Un-hardcode message_id in test backend; add console backend * Un-hardcode status message_id in test backend For the test EmailBackend, get message ID's based on array position in `mail.outbox`, so that tests can predict the message ID. * Add a console backend for use in development Adds an EmailBackend derived from both Anymail's test backend and Django's console backend, to provide anymail statuses and signal handling while printing messages to the console. For use during development on localhost. Closes #87 --- anymail/backends/console.py | 43 +++++++++++++++++++++++++++++++++++++ anymail/backends/test.py | 10 ++++++++- tests/test_send_signals.py | 4 ++-- 3 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 anymail/backends/console.py diff --git a/anymail/backends/console.py b/anymail/backends/console.py new file mode 100644 index 0000000..5fa9ffe --- /dev/null +++ b/anymail/backends/console.py @@ -0,0 +1,43 @@ +import uuid +from django.core.mail.backends.console import EmailBackend as DjangoConsoleBackend + +from ..exceptions import AnymailError +from .test import EmailBackend as AnymailTestBackend + + +class EmailBackend(AnymailTestBackend, DjangoConsoleBackend): + """ + Anymail backend that prints messages to the console, while retaining + anymail statuses and signals. + """ + + esp_name = "Console" + + def get_esp_message_id(self, message): + # Generate a guaranteed-unique ID for the message + return str(uuid.uuid4()) + + def send_messages(self, email_messages): + if not email_messages: + return + msg_count = 0 + with self._lock: + try: + stream_created = self.open() + for message in email_messages: + try: + sent = self._send(message) + except AnymailError: + if self.fail_silently: + sent = False + else: + raise + if sent: + self.write_message(message) + self.stream.flush() # flush after each message + msg_count += 1 + finally: + if stream_created: + self.close() + + return msg_count diff --git a/anymail/backends/test.py b/anymail/backends/test.py index 41f900b..b78b7d0 100644 --- a/anymail/backends/test.py +++ b/anymail/backends/test.py @@ -27,6 +27,11 @@ class EmailBackend(AnymailBaseBackend): if not hasattr(mail, 'outbox'): mail.outbox = [] # see django.core.mail.backends.locmem + def get_esp_message_id(self, message): + # Get a unique ID for the message. The message must have been added to + # the outbox first. + return mail.outbox.index(message) + def build_message_payload(self, message, defaults): return TestPayload(backend=self, message=message, defaults=defaults) @@ -41,7 +46,10 @@ class EmailBackend(AnymailBaseBackend): raise response except AttributeError: # Default is to return 'sent' for each recipient - status = AnymailRecipientStatus(message_id=1, status='sent') + status = AnymailRecipientStatus( + message_id=self.get_esp_message_id(message), + status='sent' + ) response = { 'recipient_status': {email: status for email in payload.recipient_emails} } diff --git a/tests/test_send_signals.py b/tests/test_send_signals.py index b416c14..dddd526 100644 --- a/tests/test_send_signals.py +++ b/tests/test_send_signals.py @@ -65,9 +65,9 @@ class TestPostSendSignal(TestBackendTestCase): self.assertEqual(sender, TestEmailBackend) self.assertEqual(message, self.message) self.assertEqual(status.status, {'sent'}) - self.assertEqual(status.message_id, 1) # TestEmailBackend default message_id + self.assertEqual(status.message_id, 0) self.assertEqual(status.recipients['to@example.com'].status, 'sent') - self.assertEqual(status.recipients['to@example.com'].message_id, 1) + self.assertEqual(status.recipients['to@example.com'].message_id, 0) self.assertEqual(esp_name, "Test") # the TestEmailBackend's ESP is named "Test" self.receiver_called = True self.addCleanup(post_send.disconnect, receiver=handle_post_send)