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



我正在开发一个实现用户注册系统的Flask应用程序。该应用程序使用Flask-Mail,通过电子邮件确认用户的注册和重置密码是很危险的。我将Flask-Mail配置为使用我正在使用的电子邮件主机提供的推荐服务器设置。

MAIL_PORT = 587
MAIL_USE_SSL = False
MAIL_USE_TLS = True

起初,一切都很顺利;我可以毫无问题地提交邮件。然而,似乎没有改变任何配置设置,当我试图使用Flask-Mail提交电子邮件时,我现在收到以下错误:

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

我不知道问题出在哪里,我想知道电子邮件提供商端是否发生了变化?我试过用MAIL_USE_SSL=FalseMAIL_USE_TLS=False设置MAIL_PORT = 25;MAIL_PORT = 465MAIL_USE_SSL=TrueMAIL_USE_TLS=False。使用前者,我收到与端口587相同的错误,但使用后者,我收到STARTTLS extension not supported by server.

我在localhost:5000的开发模式下运行Flask应用程序。以下是我的一些配置设置和代码:

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

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/用户/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)

app/extensions.py

from flask_mail import Mail
from flask_bootstrap import Bootstrap
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
bootstrap = Bootstrap()
mail = Mail()

应用程序/initpy

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文件中,忘记其他的…

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的答案因为"true"在VSCode中变为str而不是Python的True

回到开头,硬编码TLS为True, SSL为False在config.py文件中,然后花时间在一些有用的东西上。

我明白是怎么回事了。显然,在从Flask-Mail初始化Mail对象时,可以为MAIL_USE_TLS和MAIL_USE_SSL传入非布尔类型。当Connection对象调用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,博士确保Flask应用程序的配置变量被设置为适当的类型,特别是如果你使用的是环境变量,因为在通过操作系统访问它们时,这些变量总是str类型的。环境dict .

flask_mail.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')))

最新更新