烧瓶邮件异常

Posted

技术标签:

【中文标题】烧瓶邮件异常【英文标题】:Flask Mail Exception 【发布时间】:2015-01-11 05:16:18 【问题描述】:

我签出 6b(《Flask Web 开发》一书,第 6 章邮件),我想发送一封电子邮件进行测试。但是它引发了异常。我使用虚拟机(CentOS 7)。异常如下:

(venv)➜  flasky git:(09d4ff0) ✗ python hello.py runserver --host 0.0.0.0
 * Running on http://0.0.0.0:5000/
192.168.182.1 - - [10/Jan/2015 22:03:06] "GET / HTTP/1.1" 200 -
192.168.182.1 - - [10/Jan/2015 22:03:10] "POST / HTTP/1.1" 302 -
192.168.182.1 - - [10/Jan/2015 22:03:10] "GET / HTTP/1.1" 200 -
Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib64/python2.7/threading.py", line 811, in __bootstrap_inner
    self.run()
  File "/usr/lib64/python2.7/threading.py", line 764, in run
    self.__target(*self.__args, **self.__kwargs)
  File "hello.py", line 63, in send_async_email
    mail.send(msg)
  File "/home/qinf/flasky/venv/lib/python2.7/site-packages/flask_mail.py", line 491, in send
    with self.connect() as connection:
  File "/home/qinf/flasky/venv/lib/python2.7/site-packages/flask_mail.py", line 144, in __enter__
    self.host = self.configure_host()
  File "/home/qinf/flasky/venv/lib/python2.7/site-packages/flask_mail.py", line 158, in configure_host
    host = smtplib.SMTP(self.mail.server, self.mail.port)
  File "/usr/lib64/python2.7/smtplib.py", line 250, in __init__
    (code, msg) = self.connect(host, port)
  File "/usr/lib64/python2.7/smtplib.py", line 311, in connect
    (code, msg) = self.getreply()
  File "/usr/lib64/python2.7/smtplib.py", line 362, in getreply
    raise SMTPServerDisconnected("Connection unexpectedly closed")
SMTPServerDisconnected: Connection unexpectedly closed

我使用本地 IP,但我可以连接到互联网。我更改了一些配置:邮件、端口、用户名、密码。 hello.py 作为流:

import os
from threading import Thread
from flask import Flask, render_template, session, redirect, url_for
from flask.ext.script import Manager, Shell
from flask.ext.bootstrap import Bootstrap
from flask.ext.moment import Moment
from flask.ext.wtf import Form
from wtforms import StringField, SubmitField
from wtforms.validators import Required
from flask.ext.sqlalchemy import SQLAlchemy
from flask.ext.migrate import Migrate, MigrateCommand
from flask.ext.mail import Mail, Message

basedir = os.path.abspath(os.path.dirname(__file__))

app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'
app.config['SQLALCHEMY_DATABASE_URI'] =\
    'sqlite:///' + os.path.join(basedir, 'data.sqlite')
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
app.config['MAIL_SERVER'] = 'smtp.163.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USE_TLS'] = True
#app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME')
#app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD')
app.config['MAIL_USERNAME'] = mail
app.config['MAIL_PASSWORD'] = password
app.config['FLASKY_MAIL_SUBJECT_PREFIX'] = '[Flasky]'
app.config['FLASKY_MAIL_SENDER'] = 'Flasky Admin <flasky@example.com>'
#app.config['FLASKY_ADMIN'] = os.environ.get('FLASKY_ADMIN')
app.config['FLASKY_ADMIN'] = another_mail

manager = Manager(app)
bootstrap = Bootstrap(app)
moment = Moment(app)
db = SQLAlchemy(app)
migrate = Migrate(app, db)
mail = Mail(app)


class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    users = db.relationship('User', backref='role', lazy='dynamic')

    def __repr__(self):
        return '<Role %r>' % self.name


class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True, index=True)
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

    def __repr__(self):
        return '<User %r>' % self.username


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


def send_email(to, subject, template, **kwargs):
    msg = Message(app.config['FLASKY_MAIL_SUBJECT_PREFIX'] + ' ' + subject,
                  sender=app.config['FLASKY_MAIL_SENDER'], recipients=[to])
    msg.body = render_template(template + '.txt', **kwargs)
    msg.html = render_template(template + '.html', **kwargs)
    thr = Thread(target=send_async_email, args=[app, msg])
    thr.start()
    return thr


class NameForm(Form):
    name = StringField('What is your name?', validators=[Required()])
    submit = SubmitField('Submit')


def make_shell_context():
    return dict(app=app, db=db, User=User, Role=Role)
manager.add_command("shell", Shell(make_context=make_shell_context))
manager.add_command('db', MigrateCommand)


@app.errorhandler(404)
def page_not_found(e):
    return render_template('404.html'), 404


@app.errorhandler(500)
def internal_server_error(e):
    return render_template('500.html'), 500


@app.route('/', methods=['GET', 'POST'])
def index():
    form = NameForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.name.data).first()
        if user is None:
            user = User(username=form.name.data)
            db.session.add(user)
            session['known'] = False
            if app.config['FLASKY_ADMIN']:
                send_email(app.config['FLASKY_ADMIN'], 'New User',
                           'mail/new_user', user=user)
        else:
            session['known'] = True
        session['name'] = form.name.data
        return redirect(url_for('index'))
    return render_template('index.html', form=form, name=session.get('name'),
                           known=session.get('known', False))


if __name__ == '__main__':
    manager.run()

我无法处理这个问题。

【问题讨论】:

您确定您的主机使用 TLS 吗? @BurhanKhalid 这个问题确实是由 TLS 引起的,我禁用了 MAIL_USE_SSL 选项并更改了与我使用的邮件服务器对应的端口。现在可以了。 【参考方案1】:

我认为你应该使用 SSL。

app.config['MAIL_USE_SSL'] = True

您也可以尝试从配置中删除 TLS

【讨论】:

以上是关于烧瓶邮件异常的主要内容,如果未能解决你的问题,请参考以下文章

Flask-Mail 尝试连接到 Gmail 时超时

自定义异常 python + Sentry stacktrace

Laravel 邮件队列无限循环异常

EXCEL VBA 自动发送邮件功能异常

.net捕获全局异常并且记录日志多线程方式发送邮件提醒

Zabbix监控之不发送邮件异常附属