email_log: Inherit EmailLogBackEnd from smtp.EmailBackend.

EmailLogBackend used to create a new EmailMessage and copy
only certain values from the original EmailMultiAlternatives
object. This resulted in the loss of information and made
it harder to test PRs like
https://github.com/zulip/zulip/pull/17121.

So instead of creating a new EmailMessage, tweak and send the existing
EmailMultiAlternatives object.
This commit is contained in:
Vishnu KS 2021-01-28 23:58:34 +05:30 committed by Tim Abbott
parent 049d140557
commit edac24acf1
2 changed files with 27 additions and 39 deletions

View File

@ -10,7 +10,7 @@ from zproject.email_backends import get_forward_address
class EmailLogTest(ZulipTestCase):
def test_generate_and_clear_email_log(self) -> None:
with self.settings(EMAIL_BACKEND='zproject.email_backends.EmailLogBackEnd'), \
mock.patch('zproject.email_backends.EmailLogBackEnd.send_email_smtp'), \
mock.patch('zproject.email_backends.EmailBackend.send_messages'), \
self.assertLogs(level="INFO") as m, \
self.settings(DEVELOPMENT_LOG_EMAILS=True):
result = self.client_get('/emails/generate/')
@ -35,7 +35,7 @@ class EmailLogTest(ZulipTestCase):
self.assertEqual(get_forward_address(), forward_address)
with self.settings(EMAIL_BACKEND='zproject.email_backends.EmailLogBackEnd'):
with mock.patch('zproject.email_backends.EmailLogBackEnd.send_email_smtp'):
with mock.patch('zproject.email_backends.EmailBackend.send_messages'):
result = self.client_get('/emails/generate/')
self.assertEqual(result.status_code, 302)
self.assertIn('emails', result['Location'])

View File

@ -1,12 +1,10 @@
import configparser
import logging
import smtplib
from email.message import EmailMessage
from typing import List
from django.conf import settings
from django.core.mail import EmailMultiAlternatives
from django.core.mail.backends.base import BaseEmailBackend
from django.core.mail.backends.smtp import EmailBackend
from django.template import loader
@ -29,35 +27,7 @@ def set_forward_address(forward_address: str) -> None:
with open(settings.FORWARD_ADDRESS_CONFIG_FILE, "w") as cfgfile:
config.write(cfgfile)
class EmailLogBackEnd(BaseEmailBackend):
def send_email_smtp(self, email: EmailMultiAlternatives) -> None:
from_email = email.from_email
to = get_forward_address()
msg = EmailMessage()
msg['Subject'] = email.subject
msg['From'] = from_email
msg['To'] = to
text = email.body
html = email.alternatives[0][0]
# Here, we replace the email addresses used in development
# with chat.zulip.org, so that web email providers like Gmail
# will be able to fetch the illustrations used in the emails.
localhost_email_images_base_uri = settings.ROOT_DOMAIN_URI + '/static/images/emails'
czo_email_images_base_uri = 'https://chat.zulip.org/static/images/emails'
html = html.replace(localhost_email_images_base_uri, czo_email_images_base_uri)
msg.add_alternative(text, subtype="plain")
msg.add_alternative(html, subtype="html")
smtp = smtplib.SMTP(settings.EMAIL_HOST, settings.EMAIL_PORT)
smtp.starttls()
smtp.login(settings.EMAIL_HOST_USER, settings.EMAIL_HOST_PASSWORD)
smtp.send_message(msg)
smtp.quit()
class EmailLogBackEnd(EmailBackend):
def log_email(self, email: EmailMultiAlternatives) -> None:
"""Used in development to record sent emails in a nice HTML log"""
html_message = 'Missing HTML message'
@ -86,12 +56,30 @@ class EmailLogBackEnd(BaseEmailBackend):
with open(settings.EMAIL_CONTENT_LOG_PATH, "w+") as f:
f.write(new_email + previous_emails)
@staticmethod
def prepare_email_messages_for_forwarding(email_messages: List[EmailMultiAlternatives]) -> None:
localhost_email_images_base_uri = settings.ROOT_DOMAIN_URI + '/static/images/emails'
czo_email_images_base_uri = 'https://chat.zulip.org/static/images/emails'
for email_message in email_messages:
html_alternative = list(email_message.alternatives[0])
# Here, we replace the email addresses used in development
# with chat.zulip.org, so that web email providers like Gmail
# will be able to fetch the illustrations used in the emails.
html_alternative[0] = html_alternative[0].replace(localhost_email_images_base_uri, czo_email_images_base_uri)
email_message.alternatives[0] = tuple(html_alternative)
email_message.to = [get_forward_address()]
def send_messages(self, email_messages: List[EmailMultiAlternatives]) -> int:
for email in email_messages:
if get_forward_address():
self.send_email_smtp(email)
if settings.DEVELOPMENT_LOG_EMAILS:
num_sent = len(email_messages)
if get_forward_address():
self.prepare_email_messages_for_forwarding(email_messages)
num_sent = super().send_messages(email_messages)
if settings.DEVELOPMENT_LOG_EMAILS:
for email in email_messages:
self.log_email(email)
email_log_url = settings.ROOT_DOMAIN_URI + "/emails"
logging.info("Emails sent in development are available at %s", email_log_url)
return len(email_messages)
return num_sent