Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flask-Mail [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1123)

I'm developing a Flask application that implements a user registration system. The application uses Flask-Mail and itsdangerous to confirm a user's registration and reset their password via email. I configured Flask-Mail to use the recommended server settings provided by the email host that I'm using.

MAIL_PORT = 587
MAIL_USE_SSL = False
MAIL_USE_TLS = True

At first, things were working fine; I could submit emails without any issues. However, seemingly without changing any configuration settings, I now receive the following error when attempting to submit an email using Flask-Mail:

[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1123)

I'm not sure where the problem is, and I am wondering if something has changed on the email provider's end? I have tried setting MAIL_PORT = 25 with MAIL_USE_SSL=False and MAIL_USE_TLS=False; and, MAIL_PORT = 465 with MAIL_USE_SSL=True and MAIL_USE_TLS=False as well. Using the former, I receive the same error as with port 587, but using the latter I'm receiving STARTTLS extension not supported by server.

I'm running the Flask app in development mode at localhost:5000. Here's some of my configuration settings and code:

config.py

    SECRET_KEY = 'verysecret'
    MAIL_SERVER = "smtp.mymailservice.com"
    MAIL_PORT = 587
    MAIL_USE_SSL = False
    MAIL_USE_TLS = True
    MAIL_USERNAME = "[email protected]"
    MAIL_PASSWORD = "mypassword"
    MAIL_DEFAULT_SENDER = 'Brand <[email protected]>'

app/mailing.py

from flask_mail import Message
from flask import current_app
from .extensions import mail


def send_email(to, subject, template):
    msg = Message(
        subject,
        recipients=[to],
        html=template,
        sender=current_app.config["MAIL_DEFAULT_SENDER"]
    )
    mail.send(msg)

app/users/routes.py

(One of the routes where I receive the error)

from flask import (
    render_template, session, request, redirect, url_for, g, jsonify, flash
)

import uuid
from passlib.hash import sha256_crypt

from app.mailing import send_email
from app.extensions import db
from app.users import bp
from app.users.forms import *
from app.users.models import *
from app.users.token import *

@bp.route('/register', methods=['POST', 'GET'])
def register():

    # Initialize the Register Form
    form = RegisterForm()

    # If the submitted form is valid
    if form.validate_on_submit():

        # Check to see if a user already exists with this email address
        user = User.query.filter_by(email=form.email.data).first()

        # If there is not a user with this email address, create a new user
        if not user:
            new_user = User(public_id=str(uuid.uuid4()),
                            email=form.email.data,
                            password=sha256_crypt.encrypt(
                                (form.password.data)),
                            first_name=form.firstname.data,
                            last_name=form.lastname.data

                            )

            db.session.add(new_user)
            db.session.commit()

            token = generate_confirmation_token(new_user.email)
            confirm_url = url_for("users.confirm_email",
                                  token=token, _external=True)
            html = render_template('confirm_email.html',
                                   confirm_url=confirm_url)
            subject = "Please confirm your email"

            try:
                send_email(new_user.email, subject, html)
                flash("A confirmation email has been sent to you. Please verify your email address to activate your account.", category="success")
            except Exception as e:
                flash(
                    "There was a problem sending the confirmation email. Please try again later.", category="danger")
                print(e)

            session["user_id"] = new_user.public_id
            session["email"] = new_user.email
            session["name"] = new_user.first_name

            flash("Thanks for registering!", category="success")

            return redirect(url_for('users.unconfirmed'))
        else:
            flash("There is already an account associated with this email address. Log in, or use a different email address.")

    return render_template("register_user.html", form=form)

app/extensions.py

from flask_mail import Mail
from flask_bootstrap import Bootstrap
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()
bootstrap = Bootstrap()
mail = Mail()

app/init.py

from flask import Flask
from config import Config, DevelopmentConfig

from .errors import (
    page_not_found, forbidden, internal_server_error
)

from .extensions import (
    db, mail, bootstrap
)



def create_app(config_class=DevelopmentConfig):

    app = MyFlask(__name__)

    # Set Configuration
    app.config.from_object(config_class)
    
    # Register extensions
    # Initialize Boostrap-Flask
    bootstrap.init_app(app)

    # Initialize Flask-SQLAlchemy
    db.init_app(app)

    # Initialize Flask-Mail
    mail.init_app(app)

    # Register error views
    app.register_error_handler(404, page_not_found)
    app.register_error_handler(403, forbidden)
    app.register_error_handler(500, internal_server_error)

    with app.app_context():

        # register blueprints
        from app.main import bp as bp_main
        app.register_blueprint(bp_main)

        from app.users import bp as bp_users
        app.register_blueprint(bp_users)

        return app
like image 898
serrobit Avatar asked Mar 25 '26 21:03

serrobit


1 Answers

This answer was almost there but not quite for me. Even more TL:DR.

Put this in your config.py file and forget about the rest...

class Config:
    MAIL_USE_TLS = True
    MAIL_USE_SSL = False

More details...

You probably have a config.py file that looks like this:

class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY')
    SQLALCHEMY_DATABASE_URI = 'sqlite:///site.db' # os.environ.get('DATABASE_URI')
    MAIL_SERVER = os.environ.get('MAIL_SERVER')
    MAIL_PORT = os.environ.get('MAIL_PORT')
    MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS')
    MAIL_USE_SSL = os.environ.get('MAIL_USE_SSL')
    MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
    MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
    MAIL_DEFAULT_SENDER = os.environ.get('MAIL_DEFAULT_SENDER')

And then you think you can have something like this in your VSCode debug config or the environment of your server:

"env": {
    "MAIL_USE_SSL":"true",
    "MAIL_USE_TLS":"true",

Well that doesn't work because of the answer from @serrobit because "true" in VSCode turns into a str instead of a Python True.

So back to the start, hard code TLS to True and SSL to False in the config.py file and go spend time on something useful.

like image 59
Brian of London Avatar answered Mar 27 '26 09:03

Brian of London



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!