flask 异步发送邮件 --
异步发送邮件
当使用SMTP的方式发送电子邮件时,如果你手动使用浏览器测试程序的注册功能,在提交注册表单后,浏览器会有几秒钟的不响应。因为这时候程序正在发送电子邮件,发信的操作阻断了请求--响应循环,直到发信的send_mail()函数调用结束后,视图函数才会返回响应。这几秒的延迟带了不好的用户体验,为了避免这个延迟,我们可以将发信函数放入后台线程异步执行,以Flask-Mail为例:
app.py: 异步发送电子邮件
from threading import Thread def _send_async_mail(app, message): with app.app_context(): mail.send(message) def send_mail(subject, to, body): message = Message(subject, recipients=[to], body = body) thr = Thread(target=_send_async_mail, args=[app, message]) thr.start() return thr
因为Flask-Mail的send()方法内部的调用逻辑中使用了current_app变量,而这个变量只在激活的程序上下文中才存在,这里在后台线程调用发信函数,但是后台线程并没有程序上下文存在。为了正常实现发信功能,我们传入app作为参数,并调用app.app_context()手动激活程序上下文。
app.py文件增加相关的类和函数
#send over SMTP def send_smtp_mail(subject, to, body): message = Message(subject, recipients=[to], body=body) mail.send(message) class EmailForm(FlaskForm): to = StringField('To', validators=[DataRequired(),Email()]) subject = StringField('Subject', validators=[DataRequired()]) body = TextAreaField('Body', validators=[DataRequired()]) submit_smtp = SubmitField('Send with SMTP') submit_async = SubmitField('Send with SMTP asynchronously') #send email asynchronously def _send_async_mail(app, message): with app.app_context(): mail.send(message) def send_async_mail(subject, to ,body): message = Message(subject, recipients=[to],body=body) thr = Thread(target=_send_async_mail, args=[app, message]) thr.start() return thr @app.route('/', methods=['GET','POST']) def index(): form = EmailForm() if form.validate_on_submit(): to = form.to.data subject = form.subject.data body = form.body.data if form.submit_smtp.data: send_smtp_mail(subject, to, body) print "request.form:",request.form method = request.form.get('submit_smtp') #提交按钮的文字 else: send_async_mail(subject, to, body) print "request.form:", request.form method = request.form.get('submit_async') #提交按钮的文字 print "method:",method print "method.split():",method.split() flash('Email sent %s! Check your inbox.' % ' '.join(method.split()[1:])) #把按钮上的问题的前一个单词去掉,显示剩下的,用来提示发送方式 return redirect(url_for('index')) form.subject.data = 'Keep on learning Flask!' form.body.data = 'Across the Great Wall we can reach every corner in the world.' return render_template('index.html', form=form) if __name__ == '__main__': print app.config app.run(debug = True)
新建index.html:
{% extends 'base.html' %} {% from 'macros.html' import form_field %} {% block content %} <h2>Send an Email to Yourself</h2> <p>or subscribe <a href="{{ url_for('subscribe') }}">the fake newsletter</a></p> <form method="post"> {{ form.csrf_token }} {{ form_field(form.to, placeholder='xiaxiaoxu1987@163.com') }} {{ form_field(form.subject, size=30) }} {{ form_field(form.body, rows=5, cols=50) }}<br> {{ form.submit_smtp(class='btn') }} {{ form.submit_async(class='btn') }} </form> {% endblock %}
在测试前,确保在demos/email目录下添加一个.env文件,保存发送邮件所需要的MAIL_SERVER、MAIL_USERNAME、MAIL_PASSWORD的值。准备好后,访问index页面,在表单To字段里填入你的邮箱地址,然后单击下面的按钮发送邮件,Send with SMTP将通过普通的SMTP方式发信,Send with SMTP asynchronously则会以异步的方式通过SMTP发信。
访问127.0.0.1:5000,渲染index页面,在页面中输入你的名称和邮件,就会收到包含HTML正文的邮件。
发送Send with SMTP asynchronously: 异步发送邮件,页面立刻会看到flash消息
SMTP方式发送邮件,需要等待几秒才能看到flash消息
邮箱发送情况