0

I'm trying to create a standard 'forgot password' feature for my web application. The issue is, when the user types in their email address and clicks submit to receive a token after which they can change their password, the page just keeps loading until the following error message appears:

This page isn’t working
{{ URL }} didn’t send any data.
ERR_EMPTY_RESPONSE

I understand Flask-Mail sends emails synchronously, so this is likely an issue with connecting to Gmail. I've tried turning on "Less secure app access" on the account from which I've configured the mail object, I've also tried changing this set of configuration options:

app.config['MAIL_SERVER'] = 'smtp.googlemail.com'
app.config['MAIL_PORT'] = 587
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USERNAME'] = os.environ.get('EMAIL_USER')
app.config['MAIL_PASSWORD'] = os.environ.get('EMAIL_PASS')
mail = Mail(app)

To this:

app.config["MAIL_SERVER"] = "smtp.gmail.com"
app.config["MAIL_PORT"] = 465
app.config["MAIL_USE_TLS"] = False
app.config["MAIL_USE_SSL"] = True
app.config["MAIL_USERNAME"] = os.environ.get("EMAIL_USER")
app.config["MAIL_PASSWORD"] = os.environ.get("EMAIL_PASS")
mail = Mail(app)

which I saw suggested online but none of this has worked.

Here are the relevant routes and methods:

# Generate password reset token
def get_reset_token(current_user, expires_sec=1800):
    s = Serializer(app.config["SECRET_KEY"], expires_sec)
    return s.dumps({"user_id": current_user}).decode("utf-8")

# Send reset email
def send_reset_email(user):
    rows = db.execute("SELECT * FROM users WHERE id = :current_user", current_user = user)
    user_email = rows[0]["email"]
    token = get_reset_token(user)
    msg = Message("Password Reset Request", sender = "noreply@demo.com", recipients = [user_email])
    msg.body = f"""To reset your password, visit the following link:
{url_for('new_password', token = token, _external = True)}

If you did not make this request simply ignore this email and no changes will be made.
"""
    mail.send(msg)


@app.route("/reset", methods=["GET", "POST"])
def reset():
    if request.method == "GET":
        return render_template("reset.html")
    else:
        email = request.form.get("email")

        # Check email exists in database
        check_email = db.execute("SELECT * FROM users WHERE email = :email", email = email)
        if len(check_email) != 1:
            return apology("You must enter the email address you registered with", 403)
        else:
            user = check_email[0]["id"]
            send_reset_email(user)
            flash("An email has been sent with instructions to reset your password")
            return render_template("login.html")

In terms of debugging I've tried running the application without the mail.send(msg) and everything worked fine, minus the email being sent obviously, implying the issue is indeed with the email being sent. Additionally I tried removing the token = get_reset_token(user) function to see if that was the issue but the problem persisted.

From the terminal it seems the application gets to check_email = db.execute("SELECT * FROM users WHERE email = :email", email = email) after the email is submitted with no issue, at which point it just keeps loading until it times out.

*Edit: This is the terminal error message when the page times out

ERROR:application:Exception on /reset [POST]
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 2447, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1952, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1821, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/usr/local/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
    raise value
  File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1950, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/ubuntu/pset8/finance/application.py", line 227, in reset
    send_reset_email(user)
  File "/home/ubuntu/pset8/finance/application.py", line 211, in send_reset_email
    mail.send(msg)
  File "/home/ubuntu/.local/lib/python3.7/site-packages/flask_mail.py", line 491, in send
    with self.connect() as connection:
  File "/home/ubuntu/.local/lib/python3.7/site-packages/flask_mail.py", line 144, in __enter__
    self.host = self.configure_host()
  File "/home/ubuntu/.local/lib/python3.7/site-packages/flask_mail.py", line 156, in configure_host
    host = smtplib.SMTP_SSL(self.mail.server, self.mail.port)
  File "/usr/local/lib/python3.7/smtplib.py", line 1031, in __init__
    source_address)
  File "/usr/local/lib/python3.7/smtplib.py", line 251, in __init__
    (code, msg) = self.connect(host, port)
  File "/usr/local/lib/python3.7/smtplib.py", line 336, in connect
    self.sock = self._get_socket(host, port, self.timeout)
  File "/usr/local/lib/python3.7/smtplib.py", line 1037, in _get_socket
    self.source_address)
  File "/usr/local/lib/python3.7/socket.py", line 728, in create_connection
    raise err
  File "/usr/local/lib/python3.7/socket.py", line 716, in create_connection
    sock.connect(sa)
OSError: [Errno 99] Cannot assign requested address
INFO:werkzeug:192.168.239.121 - - [15/Oct/2020 18:28:12] "POST /reset HTTP/1.0" 500 -

This confirms the most recent line of code called was mail.send(msg)

You must log in to answer this question.

Browse other questions tagged .