flask 邮件错误“SMTPServerDisconnected('please run connect() first')”

flask mail error “SMTPServerDisconnected('please run connect() first')”

我正在编写一个基于 Miguel Grinberg 的 Flasky 的小型 Web 应用程序。我使用与用户使用 gmail 发送重置密码邮件完全相同的代码。

下面作为我的email.py文件,这里可以实现邮件发送功能

def send_password_reset_email(user):

    token = user.get_reset_password_token()
    send_email(_('[Microblog] Reset Your Password'),
               sender=current_app.config['ADMINS'][0],
               recipients=[user.email],
               text_body=render_template('email/reset_password.txt',
                                         user=user, token=token),
               html_body=render_template('email/reset_password.html',
                                         user=user, token=token))

def send_async_email(app, msg):
    with app.app_context():
        mail.send(msg)

def send_email(subject, sender, recipients, text_body, html_body):
    msg = Message(subject, sender=sender, recipients=recipients)
    msg.body = text_body
    msg.html = html_body
    Thread(target=send_async_email,
           args=(current_app._get_current_object(), msg)).start()

在 routes.py 文件中,我从用户那里收到电子邮件,如果用户电子邮件匹配,那么我会通过邮件将令牌发送给用户

@bp.route('/reset_password_request', methods=['GET', 'POST'])
def reset_password_request():
    if current_user.is_authenticated:
        return redirect(url_for('main.index'))
    form = ResetPasswordRequestForm()
    if form.validate_on_submit():
        user = User.query.filter_by(email=form.email.data).first()
        if user:
            send_password_reset_email(user)
        flash(
            _('Check your email for the instructions to reset your password'))
        return redirect(url_for('auth.login'))
    return render_template('auth/reset_password_request.html',
                           title=_('Reset Password'), form=form)


@bp.route('/reset_password/<token>', methods=['GET', 'POST'])
def reset_password(token):
    if current_user.is_authenticated:
        return redirect(url_for('main.index'))
    user = User.verify_reset_password_token(token)
    if not user:
        return redirect(url_for('main.index'))
    form = ResetPasswordForm()
    if form.validate_on_submit():
        user.set_password(form.password.data)
        db.session.commit()
        flash(_('Your password has been reset.'))
        return redirect(url_for('auth.login'))
    return render_template('auth/reset_password.html', form=form)

在用户模型的 model.py 文件中,我为用户生成一个令牌并检查用户令牌

def get_reset_password_token(self, expires_in=600):
        return jwt.encode(
            {'reset_password': self.id, 'exp': time() + expires_in},
            current_app.config['SECRET_KEY'],
            algorithm='HS256').decode('utf-8')
        
    @staticmethod
    def varify_reset_password_token(token):
        try:
            id = jwt.decode(token, current_app.config['SECRET_KEY'],
                            algorithms=['HS256'])['reset_password']
        except:
            return
        return User.query.get(id)

我的 flask 邮件设置如下 config.py 文件

    MAIL_SERVER   = os.environ.get('MAIL_SERVER')
    MAIL_PORT     = int(os.environ.get('MAIL_PORT') or 25)
    MAIL_USE_TLS  = os.environ.get('MAIL_USE_TLS') is not None
    MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
    MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
    ADMINS         =['socialtraffic@gmail.com']

终端出现以下错误

Traceback (most recent call last):

  File "c:\python38\lib\threading.py", line 932, in _bootstrap_inner
    self.run()
 
  File "c:\python38\lib\threading.py", line 870, in run     
    self._target(*self._args, **self._kwargs)
  File "C:\Users\Ijaz Bacha\project\microblog1\app\email.py", line 9, in send_async_email
    mail.send(msg)
  File "c:\users\ijaz bacha\project\microblog1\venv\lib\site-packages\flask_mail.py", line 492, in send
    message.send(connection)
  File "c:\users\ijaz bacha\project\microblog1\venv\lib\site-packages\flask_mail.py", line 152, in __exit__
    self.host.quit()
  File "c:\python38\lib\smtplib.py", line 988, in quit      
    res = self.docmd("quit")
  File "c:\python38\lib\smtplib.py", line 424, in docmd
    self.putcmd(cmd, args)
  File "c:\python38\lib\smtplib.py", line 371, in putcmd
    self.send(str)
  File "c:\python38\lib\smtplib.py", line 363, in send
    raise SMTPServerDisconnected('please run connect() first')
smtplib.SMTPServerDisconnected: please run connect() first

根据我的经验,不久前我遇到了与您遇到的问题非常相似的问题。故障排除后,我发现我的代码在创建邮件 class 并调用 $mailclass.ehlo 等函数时有效

根据错误,连接或保持连接有问题。尝试调用函数本身的连接方法并在每封电子邮件后关闭连接。

我也在做同样的教程并且 运行 遇到同样的问题。我在 Miguel's Blog:

上找到了答案

你需要两个终端windows。 第一个终端 运行 您的本地邮件服务器,它模拟您正在发送的电子邮件:

$(venv) python -m smtpd -n -c DebuggingServer localhost:8025

您的主 Flask 终端 window 使用以下必需命令(FLASK_DEBUG=1 是可选的,但强烈建议用于故障排除):

$ export FLASK_APP=microblog.py
$ export FLASK_DEBUG=1
$ export MAIL_SERVER=localhost
$ export MAIL_PORT=8025
$ flask run

这解决了我的问题。