backends: Create custom email backend EmailLogBackEnd.

Create a new custom email backend which would automatically
logs the emails that are send in the dev environment as
well as print a friendly message in console to visit /emails
for accessing all the emails that are sent in dev environment.
Since django.core.mail.backends.console.EmailBackend is no longer
userd emails would not be printed to the console anymore.
This commit is contained in:
Vishnu Ks
2017-10-03 00:04:32 +00:00
committed by Tim Abbott
parent 80fc9cda3a
commit eef72a98e4
6 changed files with 69 additions and 68 deletions

View File

@@ -1,16 +1,12 @@
{% if failed %}
<p>{{template}} failed to render: {{ reason }}</p>
{% else %}
<h4>From: {{ from_email }}</h4>
<h4>To:
{% for recipient in recipients %}
{{ recipient }}&nbsp;
{% endfor %}
</h4>
<h4>Subject: {{subject}}</h4>
{% autoescape off %}
{{ html_message }}
{% endautoescape %}
<pre>{{ body }}</pre>
{% endif %}
<h4>From: {{ from_email }}</h4>
<h4>To:
{% for recipient in recipients %}
{{ recipient }}&nbsp;
{% endfor %}
</h4>
<h4>Subject: {{subject}}</h4>
{% autoescape off %}
{{ html_message }}
{% endautoescape %}
<pre>{{ body }}</pre>
<hr/>

View File

@@ -23,35 +23,6 @@ class FromAddress(object):
SUPPORT = parseaddr(settings.ZULIP_ADMINISTRATOR)[1]
NOREPLY = parseaddr(settings.NOREPLY_EMAIL_ADDRESS)[1]
def log_email(email, template_prefix):
# type: (EmailMultiAlternatives, str) -> None
"""Used in development to record sent emails in a nice HTML log"""
html_message = 'Missing HTML message'
if len(email.alternatives) > 0:
html_message = email.alternatives[0][0]
context = {
'template': template_prefix + ".html",
'subject': email.subject,
'from_email': email.from_email,
'recipients': email.to,
'body': email.body,
'html_message': html_message
}
new_email = loader.render_to_string('zerver/email.html', context)
# Read in the pre-existing log, so that we can add the new entry
# at the top.
try:
with open(settings.EMAIL_CONTENT_LOG_PATH, "r") as f:
previous_emails = f.read()
except FileNotFoundError:
previous_emails = ""
with open(settings.EMAIL_CONTENT_LOG_PATH, "w+") as f:
f.write(new_email + previous_emails)
def build_email(template_prefix, to_user_id=None, to_email=None, from_name=None,
from_address=None, reply_to_email=None, context=None):
# type: (str, Optional[int], Optional[Text], Optional[Text], Optional[Text], Optional[Text], Optional[Dict[str, Any]]) -> EmailMultiAlternatives
@@ -117,9 +88,6 @@ def send_email(template_prefix, to_user_id=None, to_email=None, from_name=None,
template = template_prefix.split("/")[-1]
logger.info("Sending %s email to %s" % (template, mail.to))
if settings.DEVELOPMENT:
log_email(mail, template_prefix)
if mail.send() == 0:
logger.error("Error sending %s email to %s" % (template, mail.to))
raise EmailNotDeliveredException
@@ -135,13 +103,10 @@ def send_future_email(template_prefix, to_user_id=None, to_email=None, from_name
email_fields = {'template_prefix': template_prefix, 'to_user_id': to_user_id, 'to_email': to_email,
'from_name': from_name, 'from_address': from_address, 'context': context}
if settings.DEVELOPMENT:
mail = build_email(template_prefix, to_user_id=to_user_id, to_email=to_email, from_name=from_name,
from_address=from_address, context=context)
# Technically, this will be called. But we currently don't
# run the `manage.py deliver_email` backend job in the
# development environment.
log_email(mail, template_prefix)
if settings.DEVELOPMENT and not settings.TEST_SUITE:
send_email(template_prefix, to_user_id=to_user_id, to_email=to_email, from_name=from_name,
from_address=from_address, context=context)
# For logging the email
assert (to_user_id is None) ^ (to_email is None)
if to_user_id is not None:

View File

@@ -76,19 +76,19 @@ class DocPageTest(ZulipTestCase):
self._test('/errors/404/', 'Page not found')
self._test('/errors/5xx/', 'Internal server error')
# For reaching full coverage for clear_emails function
self._test('/emails/', 'manually generate most of the emails by clicking')
if os.path.isfile(settings.EMAIL_CONTENT_LOG_PATH):
os.remove(settings.EMAIL_CONTENT_LOG_PATH)
result = self.client_get('/emails/clear/')
self.assertEqual(result.status_code, 302)
result = self.client_get(result['Location'])
self.assertIn('manually generate most of the emails by clicking', str(result.content))
with self.settings(EMAIL_BACKEND='zproject.backends.EmailLogBackEnd'):
# For reaching full coverage for clear_emails function
result = self.client_get('/emails/clear/')
self.assertEqual(result.status_code, 302)
result = self.client_get(result['Location'])
self.assertIn('manually generate most of the emails by clicking', str(result.content))
result = self.client_get('/emails/generate/')
self.assertEqual(result.status_code, 302)
self.assertIn('emails', result['Location'])
self._test('/register/', 'Sign up for Zulip')
result = self.client_get('/emails/generate/')
self.assertEqual(result.status_code, 302)
self.assertIn('emails', result['Location'])
self._test('/emails/', 'manually generate most of the emails by clicking')
self._test('/register/', 'Sign up for Zulip')
result = self.client_get('/integrations/doc-html/nonexistent_integration', follow=True)
self.assertEqual(result.status_code, 404)

View File

@@ -305,7 +305,7 @@ class LoginTest(ZulipTestCase):
with queries_captured() as queries:
self.register(self.nonreg_email('test'), "test")
# Ensure the number of queries we make is not O(streams)
self.assert_length(queries, 68)
self.assert_length(queries, 66)
user_profile = self.nonreg_user('test')
self.assertEqual(get_session_dict_user(self.client.session), user_profile.id)
self.assertFalse(user_profile.enable_stream_desktop_notifications)

View File

@@ -6,6 +6,9 @@ from django.contrib.auth.backends import RemoteUserBackend
from django.conf import settings
from django.http import HttpResponse
import django.contrib.auth
from django.core.mail.backends.base import BaseEmailBackend
from django.core.mail import EmailMultiAlternatives
from django.template import loader
from django_auth_ldap.backend import LDAPBackend, _LDAPUser
from zerver.lib.actions import do_create_user
@@ -575,3 +578,40 @@ AUTH_BACKEND_NAME_MAP = {
u'LDAP': ZulipLDAPAuthBackend,
u'RemoteUser': ZulipRemoteUserBackend,
} # type: Dict[Text, Any]
class EmailLogBackEnd(BaseEmailBackend):
def log_email(self, email):
# type: (EmailMultiAlternatives) -> None
"""Used in development to record sent emails in a nice HTML log"""
html_message = 'Missing HTML message'
if len(email.alternatives) > 0:
html_message = email.alternatives[0][0]
context = {
'subject': email.subject,
'from_email': email.from_email,
'recipients': email.to,
'body': email.body,
'html_message': html_message
}
new_email = loader.render_to_string('zerver/email.html', context)
# Read in the pre-existing log, so that we can add the new entry
# at the top.
try:
with open(settings.EMAIL_CONTENT_LOG_PATH, "r") as f:
previous_emails = f.read()
except FileNotFoundError:
previous_emails = ""
with open(settings.EMAIL_CONTENT_LOG_PATH, "w+") as f:
f.write(new_email + previous_emails)
def send_messages(self, email_messages):
# type: (List[EmailMultiAlternatives]) -> int
for email in email_messages:
self.log_email(email)
email_log_url = settings.ROOT_DOMAIN_URI + "/emails"
print("You can access all the emails sent in development environment by visiting ", email_log_url)
return len(email_messages)

View File

@@ -1386,7 +1386,7 @@ elif not EMAIL_HOST and PRODUCTION:
EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend'
elif DEVELOPMENT:
# In the dev environment, emails are printed to the run-dev.py console.
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
EMAIL_BACKEND = 'zproject.backends.EmailLogBackEnd'
else:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'