简体   繁体   English

Flask-Mail [SSL: WRONG_VERSION_NUMBER] 错误的版本号 (_ssl.c:1123)

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

I'm developing a Flask application that implements a user registration system.我正在开发一个实现用户注册系统的 Flask 应用程序。 The application uses Flask-Mail and itsdangerous to confirm a user's registration and reset their password via email.该应用程序使用 Flask-Mail 和 itsdangerous 来确认用户的注册并通过 email 重置他们的密码。 I configured Flask-Mail to use the recommended server settings provided by the email host that I'm using.我将 Flask-Mail 配置为使用我正在使用的 email 主机提供的推荐服务器设置。

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:但是,似乎没有更改任何配置设置,我现在在尝试使用 Flask-Mail 提交 email 时收到以下错误:

[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1123) [SSL: 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?我不确定问题出在哪里,我想知道 email 提供商端是否发生了变化? I have tried setting MAIL_PORT = 25 with MAIL_USE_SSL=False and MAIL_USE_TLS=False ;我尝试使用MAIL_USE_SSL=FalseMAIL_USE_TLS=False设置MAIL_PORT = 25 and, MAIL_PORT = 465 with MAIL_USE_SSL=True and MAIL_USE_TLS=False as well.并且, MAIL_PORT = 465 ,同时MAIL_USE_SSL=TrueMAIL_USE_TLS=False 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.使用前者,我收到与端口 587 相同的错误,但使用后者我收到STARTTLS extension not supported by server.

I'm running the Flask app in development mode at localhost:5000.我在 localhost:5000 以开发模式运行 Flask 应用程序。 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 = "myemail@myhostname.com"
    MAIL_PASSWORD = "mypassword"
    MAIL_DEFAULT_SENDER = 'Brand <noreply@myhostname.com>'

app/mailing.py应用程序/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应用程序/用户/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应用程序/扩展程序.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应用程序/初始化.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

This answer was almost there but not quite for me.这个答案几乎就在那里,但对我来说并不完全。 Even more TL:DR.更多 TL:DR。

Put this in your config.py file and forget about the rest...把它放在你的config.py文件中,忘记 rest...

class Config:
    MAIL_USE_TLS = True
    MAIL_USE_SSL = False

More details...更多细节...

You probably have a config.py file that looks like this:您可能有一个如下所示的config.py文件:

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:然后你认为你可以在你的 VSCode 调试配置或你的服务器环境中有这样的东西:

"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 .好吧,由于@serrobit 的回答,这不起作用,因为 VSCode 中的“true”变成了str而不是 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.回到开头,在 config.py 文件中将 TLS 硬编码为 True,将 SSL 硬编码为 False,go 将时间花在有用的东西上。

I figured out what was going on.我弄清楚发生了什么事。 Evidently, you can pass in non-boolean types for MAIL_USE_TLS and MAIL_USE_SSL when initializing the Mail object from Flask-Mail.显然,在从 Flask-Mail 初始化 Mail object 时,您可以为 MAIL_USE_TLS 和 MAIL_USE_SSL 传入非布尔类型。 This becomes a problem when the Connection object calls configure_host() and conditionally checks if self.mail.use_ssl .当 Connection object 调用 configure_host() 并有条件地检查if self.mail.use_ssl时,这将成为一个问题。

Thus, as long as self.mail.use_ssl is not None , the method will set host = smtplib.SMTP_SSL(self.mail.server, self.mail.port) , which in my case, lead to [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1123) because mail.port was set to 587.因此,只要self.mail.use_ssl不是None ,该方法就会设置host = smtplib.SMTP_SSL(self.mail.server, self.mail.port) ,在我的情况下,这会导致 [SSL: WRONG_VERSION_NUMBER] 错误版本号 (_ssl.c:1123) 因为mail.port设置为 587。

tl;dr Ensure the configuration variables for your Flask app are set to the appropriate type, especially if you are using environment variables, as those will always be of type str when accessing them via the os.environ dict. tl;dr 确保您的 Flask 应用程序的配置变量设置为适当的类型,尤其是在您使用环境变量时,因为当通过 os.environ dict 访问它们时,它们将始终为 str 类型。

flask_mail.py烧瓶邮件.py

class Connection(object):
    """Handles connection to host."""

    def __init__(self, mail):
        self.mail = mail

    def __enter__(self):
        if self.mail.suppress:
            self.host = None
        else:
            self.host = self.configure_host()

        self.num_emails = 0

        return self

    def __exit__(self, exc_type, exc_value, tb):
        if self.host:
            self.host.quit()
    
    def configure_host(self):
    ## PROBLEM OCCURRED HERE BECAUSE type(self.mail.use_ssl) = <class 'str'> ##
        if self.mail.use_ssl:
            host = smtplib.SMTP_SSL(self.mail.server, self.mail.port)
        else:
            host = smtplib.SMTP(self.mail.server, self.mail.port)

        host.set_debuglevel(int(self.mail.debug))

        if self.mail.use_tls:
            host.starttls()
        if self.mail.username and self.mail.password:
            host.login(self.mail.username, self.mail.password)

        return host

Change this in your config.py :在你的config.py中改变它:

class Config:
   MAIL_USE_TLS = bool(strtobool(os.environ.get('MAIL_USE_TLS', 'False')))
   MAIL_USE_SSL = bool(strtobool(os.environ.get('MAIL_USE_SSL', 'False')))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 python 请求:(SSLError(1, '[SSL: WRONG_VERSION_NUMBER] 错误的版本号 (_ssl.c:1123)')) - python requests: (SSLError(1, '[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1123)')) 如何修复 ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] 错误的版本号 (_ssl.c:1056)? - How to fix ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1056)? python elasticsearch elasticsearch.exceptions.SSLError: ConnectionError([SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1056)) - python elasticsearch elasticsearch.exceptions.SSLError: ConnectionError([SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1056)) SSL:PYTHON 请求上的 WRONG_VERSION_NUMBER - SSL: WRONG_VERSION_NUMBER ON PYTHON REQUEST django2.1发送电子邮件失败:ssl.SSLError:[SSL:WRONG_VERSION_NUMBER]版本号错误(_ssl.c:833) - django2.1 send email fail:ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:833) jupyter SSL:WRONG_VERSION_NUMBER - jupyter SSL: WRONG_VERSION_NUMBER elastic_transport.TlsError:TLS错误导致:TlsError(TLS错误导致:SSLError([SSL:WRONG_VERSION_NUMBER]版本号错误(_ssl.c:852))) - elastic_transport.TlsError: TLS error caused by:TlsError(TLS error caused by: SSLError([SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:852))) Python-Django [SSL:WRONG_VERSION_NUMBER]错误 - Python-Django [SSL: WRONG_VERSION_NUMBER] Error 如何修复错误 ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] 版本号错误? - How to fix the error ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number? python 3 smtplib 异常:“SSL:WRONG_VERSION_NUMBER”登录到 Outlook - python 3 smtplib exception: 'SSL: WRONG_VERSION_NUMBER' logging in to outlook
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM