emails: Fix outgoing email handling inside the dev environment.

Commit 9afde790c6 introduced a bug
concerning outgoing emails inside the development environment. These
emails are not supposed to use a real connection with a mail
server as the send_messages function is overwritten inside the
EmailLogBackEnd class.

The bug was happening inside the initialize_connection function that
was introduced in the above-mentioned commit. This function is used
to refresh the connection with an SMTP server that would have closed
it. As the socket used to communicate with the server is not
initialized inside the development environment this function was
wrongly trying to send no-op commands.

The fix just checks that the connection argument of the function is
an EmailLogBackEnd object before trying the no-op command.
Additionally as it is sometimes useful to be able to send outgoing
emails inside the development environment the get_forward_address
function is used to check if a real connection exists between Zulip
and the server. If it is the case, as EmailLogBackEnd is a subclass
of smtp.EmailBackend, the connection will be nicely refreshed.

This commit was tested manually by checking that the console prints
correctly that an email is sent to the user when it signs in inside
the development environment. It was also tested when a mail provider
is specified and the mails were correctly received.
This commit is contained in:
pletinckxc 2021-04-28 20:23:14 +02:00 committed by Tim Abbott
parent 31105b78f2
commit 184df7e656
2 changed files with 16 additions and 1 deletions

View File

@ -27,6 +27,7 @@ from confirmation.models import generate_key, one_click_unsubscribe_link
from scripts.setup.inline_email_css import inline_template
from zerver.lib.logging_util import log_to_file
from zerver.models import EMAIL_TYPES, Realm, ScheduledEmail, UserProfile, get_user_profile_by_id
from zproject.email_backends import EmailLogBackEnd, get_forward_address
MAX_CONNECTION_TRIES = 3
@ -256,10 +257,22 @@ def send_email(
def initialize_connection(connection: Optional[BaseEmailBackend] = None) -> BaseEmailBackend:
if not connection:
connection = get_connection()
if connection.open():
# If it's a new connection, no need to no-op to check connectivity
return connection
# No-op to ensure that we don't return a connection that has been closed by the mail server
if isinstance(connection, EmailLogBackEnd) and not get_forward_address():
# With the development environment backend and without a
# configured forwarding address, we don't actually send emails.
#
# As a result, the connection cannot be closed by the server
# (as there is none), and `connection.noop` is not
# implemented, so we need to return the connection early.
return connection
# No-op to ensure that we don't return a connection that has been
# closed by the mail server.
if isinstance(connection, EmailBackend):
try:
status = connection.connection.noop()[0]
@ -269,6 +282,7 @@ def initialize_connection(connection: Optional[BaseEmailBackend] = None) -> Base
# Close and connect again.
connection.close()
connection.open()
return connection

View File

@ -1,3 +1,4 @@
# https://zulip.readthedocs.io/en/latest/subsystems/email.html#testing-in-a-real-email-client
import configparser
import logging
from typing import List