python / pythondotorg

Source code for python.org
https://www.python.org
Apache License 2.0
1.51k stars 601 forks source link

Use Celery to send emails #1080

Open berkerpeksag opened 7 years ago

berkerpeksag commented 7 years ago

I'm starting to see a few of these exceptions on Sentry lately:

SMTPServerDisconnected: Connection unexpectedly closed
  File "django/core/handlers/base.py", line 111, in get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "django/views/generic/base.py", line 69, in view
    return self.dispatch(request, *args, **kwargs)
  File "django/utils/decorators.py", line 29, in _wrapper
    return bound_func(*args, **kwargs)
  File "django/views/decorators/debug.py", line 76, in sensitive_post_parameters_wrapper
    return view(request, *args, **kwargs)
  File "django/utils/decorators.py", line 25, in bound_func
    return func.__get__(self, type(self))(*args2, **kwargs2)
  File "allauth/account/views.py", line 173, in dispatch
    return super(SignupView, self).dispatch(request, *args, **kwargs)
  File "allauth/account/views.py", line 68, in dispatch
    **kwargs)
  File "allauth/account/views.py", line 151, in dispatch
    **kwargs)
  File "django/views/generic/base.py", line 87, in dispatch
    return handler(request, *args, **kwargs)
  File "allauth/account/views.py", line 84, in post
    response = self.form_valid(form)
  File "allauth/account/views.py", line 189, in form_valid
    self.get_success_url())
  File "allauth/account/utils.py", line 167, in complete_signup
    signal_kwargs=signal_kwargs)
  File "allauth/account/utils.py", line 131, in perform_login
    send_email_confirmation(request, user, signup=signup)
  File "allauth/account/utils.py", line 296, in send_email_confirmation
    signup=signup)
  File "allauth/account/models.py", line 58, in send_confirmation
    confirmation.send(request, signup=signup)
  File "allauth/account/models.py", line 122, in send
    get_adapter().send_confirmation_mail(request, self, signup)
  File "allauth/account/adapter.py", line 355, in send_confirmation_mail
    ctx)
  File "allauth/account/adapter.py", line 102, in send_mail
    msg.send()
  File "django/core/mail/message.py", line 286, in send
    return self.get_connection(fail_silently).send_messages([self])
  File "django/core/mail/backends/smtp.py", line 92, in send_messages
    new_conn_created = self.open()
  File "django/core/mail/backends/smtp.py", line 59, in open
    self.connection.login(self.username, self.password)
  File "python3.4/smtplib.py", line 642, in login
    "%s %s" % (AUTH_LOGIN, encode_base64(user.encode('ascii'), eol='')))
  File "python3.4/smtplib.py", line 404, in docmd
    return self.getreply()
  File "python3.4/smtplib.py", line 376, in getreply
    raise SMTPServerDisconnected("Connection unexpectedly closed")

I think it's time to use a more robust approach.

Also, unless I'm missing something, we also use a third-party service to send emails. If so, we should implement a retry logic for that.

malemburg commented 7 years ago

It's probably better and easier to use a local postfix relay to handle sending emails and take care of retries, etc.

berkerpeksag commented 7 years ago

Would that solve timeout issues too? Right now, sending an email is a blocking task and I think users shouldn't wait for a response or get an exception from the SMTP server.

malemburg commented 7 years ago

Yes. Postfix will accept the outgoing email right away and then deal with trying to send the email to the recipient (with retries over a period of a few days if needed).