簡體   English   中英

Flask-Mail [SSL: WRONG_VERSION_NUMBER] 錯誤的版本號 (_ssl.c:1123)

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

我正在開發一個實現用戶注冊系統的 Flask 應用程序。 該應用程序使用 Flask-Mail 和 itsdangerous 來確認用戶的注冊並通過 email 重置他們的密碼。 我將 Flask-Mail 配置為使用我正在使用的 email 主機提供的推薦服務器設置。

MAIL_PORT = 587
MAIL_USE_SSL = False
MAIL_USE_TLS = True

起初,一切正常。 我可以毫無問題地提交電子郵件。 但是,似乎沒有更改任何配置設置,我現在在嘗試使用 Flask-Mail 提交 email 時收到以下錯誤:

[SSL: WRONG_VERSION_NUMBER] 錯誤的版本號 (_ssl.c:1123)

我不確定問題出在哪里,我想知道 email 提供商端是否發生了變化? 我嘗試使用MAIL_USE_SSL=FalseMAIL_USE_TLS=False設置MAIL_PORT = 25 並且, MAIL_PORT = 465 ,同時MAIL_USE_SSL=TrueMAIL_USE_TLS=False 使用前者,我收到與端口 587 相同的錯誤,但使用后者我收到STARTTLS extension not supported by server.

我在 localhost:5000 以開發模式運行 Flask 應用程序。 這是我的一些配置設置和代碼:

配置文件

    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>'

應用程序/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)

應用程序/用戶/routes.py

(我收到錯誤的路線之一)

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)

應用程序/擴展程序.py

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

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

應用程序/初始化.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

這個答案幾乎就在那里,但對我來說並不完全。 更多 TL:DR。

把它放在你的config.py文件中,忘記 rest...

class Config:
    MAIL_USE_TLS = True
    MAIL_USE_SSL = False

更多細節...

您可能有一個如下所示的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')

然后你認為你可以在你的 VSCode 調試配置或你的服務器環境中有這樣的東西:

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

好吧,由於@serrobit 的回答,這不起作用,因為 VSCode 中的“true”變成了str而不是 Python True

回到開頭,在 config.py 文件中將 TLS 硬編碼為 True,將 SSL 硬編碼為 False,go 將時間花在有用的東西上。

我弄清楚發生了什么事。 顯然,在從 Flask-Mail 初始化 Mail object 時,您可以為 MAIL_USE_TLS 和 MAIL_USE_SSL 傳入非布爾類型。 當 Connection object 調用 configure_host() 並有條件地檢查if self.mail.use_ssl時,這將成為一個問題。

因此,只要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 確保您的 Flask 應用程序的配置變量設置為適當的類型,尤其是在您使用環境變量時,因為當通過 os.environ dict 訪問它們時,它們將始終為 str 類型。

燒瓶郵件.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

在你的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM