flask 电子邮件Flask-Mail
电子邮件
在web程序中,经常会需要发送电子邮件。比如,在用户注册账户时发送确认邮件;定期向用户发送热门内容或是促销信息等等。在Web程序中发送电子邮件并不复杂,借助扩展Flask-Mail或是第三方邮件服务,只需要几行代码就可以发送邮件。
下面例子中,我们使用一封示例邮件,邮件仅包含几个必要的字段,如下:

标准的收信方和发信方字符串由姓名和邮箱地址两部分组成,,二者由空格相隔,比如“姓名 <Email地址>”。字符串中的姓名是可选的,收信方一般可以不写姓名,这时可以直接写出邮箱地址,比如”hello@example.com”。
使用Flask-Mail发送电子邮件
扩展Flask-Mail包装了python标准库中的smtplib包,简化了Flask程序中发送电子邮件的过程。我们使用pipenv安装Flask-Mail:
(Lenovo-ezd1lI9Y) C:\Users\Lenovo>pipenv install flask-mail
Installing flask-mail...
Adding flask-mail to Pipfile's [packages]...
Installation Succeeded

和其他扩展类似,我们实例化Flask-Mail提供的Mail类并传入程序实例以完成初始化,如下所示:
from flask_mail import Mail app = Flask(__name__)
mail = Mail(app)
配置Flask-Mail
Flask_Mail通过链接SMTP(Simple Mail Transfer Protocol,简单邮件传输协议)服务器来发送邮件。因此,在开始发送电子邮件前,我们需要配置SMTP服务器。如果电脑上已经设置了SMTP服务器,那么无需过多的配置即可使用,默认的邮件服务器配置即为localhost,端口为25.
在开发和测试阶段,我们可以使用邮件服务提供商的SMTP服务器(比如Bmail),这时我们需要对Flask-Mail进行配置。下面列出了Flask-Mail提供的常用配置变量。

对发送的邮件进行加密可以避免邮件在发送过程中被第三方截获和篡改。SSL(Security Socket Layer,安全套接字层)和TLS(Transport Layer Sceurity,传输层安全)是两种常用的电子邮件安全协议。TLS继承了SSL,并在SSL的基础上做了一些改进(TLS是后期版本的SSL)。所以,在大多数情况下,名词SSL和TLS可以互换使用。他们通过将MAIL_USE_SSL设置为True开启。STARTTLS是另一种加密方式,它会对不安全的连接进行升级(使用SSL或TLS)。尽管它的名字中包含TLS,但也可能会使用SSL加密。根据加密的方式不同,端口也要相应改变,如下所示:
SSL/TLS加密
MAIL_USE_SSL = True
MAIL_PORT = 465
STARTTLS加密
MAIL_USE_TLS = True
MAIL_PORT = 587
当不对邮件进行加密时,邮件服务器的端口使用默认的25端口。
常用的电子邮箱服务提供商的SMTP配置信息如下所示:

163邮箱的SMTP服务器不支持STARTTLS,你需要使用SSL/TLS加密。集体来说就是将MAIL_USE_SSL设为True,MAIL_PORT设为465.
要使用这些邮箱服务,需要访问对应的网站注册一个账户。开启邮箱的SMTP服务和获取授权码等操作均可以在个邮箱主页-设置(-账户)中找到。
Gmail、Outlook、QQ邮箱等这类服务被称为EPA(Email Service Provider),只适用于个人业务使用,不适合用来发送事务邮件(Transactional Email)。对于需要发送大量邮件的事务型邮件任务,更好的选择是使用自己设置的SMTP服务器或是类似SendGrid、Mailgun的事务邮件服务提供商(Transactional Email Service),后边会具体介绍。
在程序中,随着配置逐渐增多,我们改用app.config对象的update()方法来加载配置:
app.py:邮件服务器配置
from flask import Flask
from flask_mail import Mail app = Flask(__name__)
app.config.update(
MAIL_SERVER = os.getenv('MAIL_SERVER'),
MAIL_PORT = 678,
MAIL_USE_TLS = True,
MAIL_USEERNAME = os.getenv('MAIL_USERNAME'),
MAIL_PASSWORD = os.getenv('MAIL_PASSWORD'),
MAIL_DEFAULT_SENDER = ('Grey Li', os.getenv('MAIL_USERNAME'))
) mail = Mail(app)
在实例化Mail类时,Flask-Mail会获取配置以创建一个用于发信的对象,所以确保在实例化Mail类之前加载配置。
在我们的配置中,邮箱账户的密码属于敏感信息,不能直接写在脚本中,所以设置为从系统变量中获取。另外,在生产环境中,我们通常会使用不同的邮件服务器地址,所以这里也从环境变量中读取。
你可以使用export/set命令设置环境变量,为了方便管理,我们把这些环境变量存储在.env文件中:
MAIL_SERVER = 'smtp.qq.com'
MAIL_USERNAME = '367224698@qq.com'
MAIL_PASSWORD = 'ljfitqzfphlibjdj'
注意MAIL_PASSWORD是在qq邮箱的设置-账户中通过手机发送短信,获取的授权码,并不是qq的密码,需要开发smtp服务

默认发信人由一个两元素元祖组成,即(姓名,邮箱地址),比如:
MAIL_DEFAULT_SENDER = ('Your Name', 'your_name@example.com')
需要注意,使用邮件服务提供商提供的SMTP服务器发信时,发信人字符串中的邮件地址必须和邮箱地址相同,你可以直接只用MAIL_USERNAME的值构建发信人地址:
MAIL_DEFAULT_SENDER = ('Your Name', os.getenv('MAIL_USERNAME'))
Flask-Mail会把这个元祖转换为标准的发信人格式,即Your Name <your_name@example.com>。 你可以直接以这种方式指定发信人,比如:
MAIL_DEFAULT_SENDER = 'Your Name <your_name@example.com>'
设置默认发信人后,在发信时就可以不用再指定发信人。
构建邮件数据
下面我们借助Python shell演示发送邮件的过程。邮件通过从Flask-Mail中导入的Message类表示,而发信功能通过我们在程序包的构造文件中创建的mail对象实现,我们先进性导入:
>>> from flask_mail import Message
>>> from app import mail
一封邮件至少要包含主题、收件人、正文、发信人这几个元素。发信人(sender)在前面我们已经使用MAIL_DEFAULT_SENDER配置变量指定过了,剩下的分别通过Message类的构造方法中的subject、recipients、body关键字传入参数,其中recipients为一个包含电子邮件地址的列表。
message = Message(subject = 'title', recipients=['367224698@qq.com'], body='body')
加载环境变量方式:
1、flask项目可以通过.env加载环境变量,加载方式是运行 flask run或flask shell时加载
2、pipenv也可以通过.env加载环境变量,进入pipenv shell虚拟环境后,修改.env环境变量后再启动flask app: flask run,flask还是会用原来的环境变量,原因是pipenv shell加载了环境变量并进行了缓存,然后flask加载环境变量时不会进行覆盖。
此时可以退出pipenv shell然后再重新进入
和发信人字符串类似,收信人字符串可以为两种形式:
‘Sam <sam@example.com>’或’sam@example.com’。
发送邮件
>>>mail.send(message)
完整的发送实例邮件的代码如下:
>>> from flask_mail import Message
>>> from app import mail
>>> app.config['MAIL_PORT']
''
>>> message = Message(subject = 'title', recipients=['367224698@qq.com'], body='body')
>>> mail.send(message)
在实际操作时,报了错误:SMTPSenderRefused: (503, 'Error: need EHLO and AUTH first !', u'367224698@qq.com'),原因尚未搞清楚,配置都感觉ok,但还是报错,怀疑是QQ邮箱服务器以为我的恶意的客户端。。。
>>> from flask_mail import Message
>>> from app import mail
>>> app.config['MAIL_PORT']
''
>>> message = Message(subject = 'title', recipients=['367224698@qq.com'], body='body')
>>> mail.send(message)
send: 'ehlo [172.20.10.4]\r\n'
reply: '250-smtp.qq.com\r\n'
reply: '250-PIPELINING\r\n'
reply: '250-SIZE 73400320\r\n'
reply: '250-AUTH LOGIN PLAIN\r\n'
reply: '250-AUTH=LOGIN\r\n'
reply: '250-MAILCOMPRESS\r\n'
reply: '250 8BITMIME\r\n'
reply: retcode (250); Msg: smtp.qq.com
PIPELINING
SIZE 73400320
AUTH LOGIN PLAIN
AUTH=LOGIN
MAILCOMPRESS
8BITMIME
send: u'mail FROM:<367224698@qq.com> size=263\r\n'
reply: '503 Error: need EHLO and AUTH first !\r\n'
reply: retcode (503); Msg: Error: need EHLO and AUTH first !
send: 'rset\r\n'
reply: '250 Ok\r\n'
reply: retcode (250); Msg: Ok
send: 'quit\r\n'
reply: '221 Bye\r\n'
reply: retcode (221); Msg: Bye
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "c:\users\lenovo\.virtualenvs\lenovo-ezd1li9y\lib\site-packages\flask_mail.py", line 492, in send
message.send(connection)
File "c:\users\lenovo\.virtualenvs\lenovo-ezd1li9y\lib\site-packages\flask_mail.py", line 427, in send
connection.send(self)
File "c:\users\lenovo\.virtualenvs\lenovo-ezd1li9y\lib\site-packages\flask_mail.py", line 192, in send
message.rcpt_options)
File "c:\python27\Lib\smtplib.py", line 737, in sendmail
raise SMTPSenderRefused(code, resp, from_addr)
SMTPSenderRefused: (503, 'Error: need EHLO and AUTH first !', u'367224698@qq.com')
flask_mail发送163邮件
下面用163邮箱试一下
先进入163邮件开启smtp服务,获取授权码
授权码就是客户端登录163邮箱时的密码,用户名就是邮箱地址



获取授权码后,记录下来
在.env文件中设置邮箱信息,在命令行中运行flask shell时,会自动到该文件中获取环境变量
email\.env:
FLASK_ENV=development
MAIL_SERVER = 'smtp.163.com'
MAIL_USERNAME = 'xiaxiaoxu1987@163.com'
MAIL_PASSWORD = 'FOREVER022941' email\app.py:
from flask import Flask from flask_mail import Mail, Message import os app = Flask(__name__)
app.jinja_env.trim_blocks = True
app.jinja_env.lstrip_blocks = True #设置app.config信息,重点是用户名和密码
app.config.update(
SECRET_KEY = "SECRET KEY",
MAIL_SERVER = os.getenv('MAIL_SERVER'),
MAIL_PORT = 465,
#MAIL_PORT = 587,
#MAIL_USE_TLS = True,
MAIL_USE_SSL = True,
MAIL_USERNAME = os.getenv('MAIL_USERNAME'),
MAIL_PASSWORD = os.getenv('MAIL_PASSWORD'),
MAIL_DEFAULT_SENDER = (os.getenv('MAIL_USERNAME'))
)
命令行界面,操作发送邮件
>>> from flask_mail import Message
>>> from app import mail
>>> msg = Message('text', sender = 'xiaxiaoxu1987@163.com', recipients=['367224698@qq.com'])
>>> msg.body = 'body'
>>> mail.send(msg)
send: 'ehlo [172.20.10.4]\r\n'
reply: '250-mail\r\n'
reply: '250-PIPELINING\r\n'
reply: '250-AUTH LOGIN PLAIN\r\n'
reply: '250-AUTH=LOGIN PLAIN\r\n'
reply: '250-coremail 1Uxr2xKj7kG0xkI17xGrU7I0s8FY2U3Uj8Cz28x1UUUUU7Ic2I0Y2UrHJsU2UCa0xDrUUUUj\r\n'
reply: '250-STARTTLS\r\n'
reply: '250 8BITMIME\r\n'
reply: retcode (250); Msg: mail
PIPELINING
AUTH LOGIN PLAIN
AUTH=LOGIN PLAIN
coremail 1Uxr2xKj7kG0xkI17xGrU7I0s8FY2U3Uj8Cz28x1UUUUU7Ic2I0Y2UrHJsU2UCa0xDrUUUUj
STARTTLS
8BITMIME
send: 'AUTH PLAIN AHhpYXhpYW94dTE5ODdAMTYzLmNvbQBGT1JFVkVSMDIyOTQx\r\n'
reply: '235 Authentication successful\r\n'
reply: retcode (235); Msg: Authentication successful
send: u'mail FROM:<xiaxiaoxu1987@163.com>\r\n'
reply: '250 Mail OK\r\n'
reply: retcode (250); Msg: Mail OK
send: u'rcpt TO:<367224698@qq.com>\r\n'
reply: '250 Mail OK\r\n'
reply: retcode (250); Msg: Mail OK
send: 'data\r\n'
reply: '354 End data with <CR><LF>.<CR><LF>\r\n'
reply: retcode (354); Msg: End data with <CR><LF>.<CR><LF>
data: (354, 'End data with <CR><LF>.<CR><LF>')
send: 'Content-Type: text/plain; charset="utf-8"\r\nMIME-Version: 1.0\r\nContent-Transfer-Encoding: 7bit\r\nSubject: text\r\nFrom: xiaxiaoxu1987@163.com\r\nTo: 367224698@qq.com\r\nDate: Wed, 10 Apr 2019 21:13:57 +0800\r\nMessage-ID: <155490203514.14300.10708927723623278864@DESKTOP-F82U4NJ>\r\n\r\nbody\r\n.\r\n'
reply: '250 Mail OK queued as smtp11,D8CowACXrmER7K1cTRnVFA--.36353S2 1554902035\r\n'
reply: retcode (250); Msg: Mail OK queued as smtp11,D8CowACXrmER7K1cTRnVFA--.36353S2 1554902035
data: (250, 'Mail OK queued as smtp11,D8CowACXrmER7K1cTRnVFA--.36353S2 1554902035')
send: 'quit\r\n'
reply: '221 Bye\r\n'
reply: retcode (221); Msg: Bye
查看邮箱发送结果:

为了方便重用,我们把这些代码包装成一个通用的发信函数send_mail(),如下所示:
app.py: 通用发信函数
from flask import Flask
from flask_mail import Mail, Message
import os app = Flask(__name__)
app.config.update(
MAIL_SERVER = os.getenv('MAIL_SERVER'),
MAIL_PORT = '',
#MAIL_USE_TLS = True,
MAIL_USE_SSL = True,
MAIL_USEERNAME = os.getenv('MAIL_USERNAME'),
MAIL_PASSWORD = os.getenv('MAIL_PASSWORD'),
MAIL_DEFAULT_SENDER = (os.getenv('MAIL_USERNAME'))
) mail = Mail(app) def send_mail(subject, to, body):
message = Message(subject, recipients = [to], body = body)
mail.send(message)
假设我们的程序时一个周刊订阅程序,当用户在表单中填写了正确的email地址时,我们就发送一封邮件来通知用户订阅成功。通过在index视图中调用send_email()即可发送邮件,如下所示: 在视图函数中发送邮件
@app.route('/subscribe', methods = ['GET', 'POST'])
def subscribe():
form = SubscribeForm()
if form.validate_on_submit():
name = form.name.data
email = form.email.data
send_subscribe_mail('Subscribe Success!', email, name = name)
flash('Confirmation email have been sent! Check your inbox.')
return redirect(url_for('subscribe'))
return render_template('subscribe.html', form = form)
flask 电子邮件Flask-Mail的更多相关文章
- flask 电子邮件进阶实践-用模板发送163邮件
电子邮件进阶实践 下面来学习构建邮件的HTML正文,并使用模板组织内容. 一封电子邮件的正文可以是纯文本(text/plain),也可以是HTML格式的文本(text/html).处于全面的考虑,一封 ...
- Python flask 基于 Flask 提供 RESTful Web 服务
转载自 http://python.jobbole.com/87118/ 什么是 REST REST 全称是 Representational State Transfer,翻译成中文是『表现层状态转 ...
- [Flask]学习Flask第三天笔记总结
from flask import Flask,render_template,request from others import checkLogin app = Flask(__name__) ...
- Flask01 初识flask、flask配置
1 什么是flask Flask是一个使用 Python 编写的轻量级 Web 应用框架.其 WSGI 工具箱采用 Werkzeug ,模板引擎则使用 Jinja2 . 百度百科:点击前往 中文文档: ...
- 【Flask】Flask学习笔记(一) 应用基本结构
初始化 使用前必须创建一个应用实例 from flask import Flask app = Flask(__name__) 路由和视图函数 请求流程 客户端(web浏览器)--> web服 ...
- python框架之Flask(1)-Flask初使用
Flask是一个基于 Python 开发并且依赖 jinja2 模板和 Werkzeug WSGI 服务的一个微型框架,对于 Werkzeug 本质是 Socket 服务端,其用于接收 http 请求 ...
- cannot import name 'Flask' from 'flask'
今天发现了智障的真我. 刚入门flask,建了一个文件命名叫flask.py 在virtualenv的容器里运行该py文件,报错cannot import name 'Flask' from 'fla ...
- flask框架----flask中的wtforms使用
一.简单介绍flask中的wtforms WTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证. 安装: pip3 install wtforms 二.简单使用wtfo ...
- flask框架----flask基础
知识点回顾 1.flask依赖wsgi,实现wsgi的模块:wsgiref,werkzeug,uwsgi 2.实例化Flask对象,里面是有参数的 app = Flask(__name__,templ ...
随机推荐
- JS功能函数
1.整数每三位增加一个, function toThousands(num) { return (num || 0).toString().replace(/(\d)(?=(?:\d{3}) ...
- Installation of CarbonData 1.1.0 with Spark 1.6.2
关键词:carbondata spark thrift 数据仓库 [Install thrift 0.9.3] 注意 要装thrift-java必须先装ant . 有人说要装boost,我在cento ...
- tp3.2 模块单独配置数据库
一 $User = M('test','tp_','mysql://root:123456@localhost/new_lezhu#utf8'); 1.test -->表名 2.tp ...
- jQuery插件开发的五种形态小结(转)
关于jQuery插件的开发自己也做了少许研究,自己也写过多个插件,在自己的团队了也分享过一次关于插件的课.开始的时候整觉的很复杂的代码,现在再次看的时候就清晰了许多.这里我把我自己总结出来的东西分享出 ...
- Python 面试中可能会被问到的30个问题
第一家公司问的题目 1 简述解释型和编译型编程语言? 解释型语言编写的程序不需要编译,在执行的时候,专门有一个解释器能够将VB语言翻译成机器语言,每个语句都是执行的时候才翻译.这样解释型语言每执行一次 ...
- 深入理解iostat
前言 iostat算是比较重要的查看块设备运行状态的工具,相信大多数使用Linux的同学都用过这个工具,或者听说过这个工具.但是对于这个工具,引起的误解也是最多的,大多数人对这个工具处于朦朦胧胧的状态 ...
- 树莓派与Linux系统之间文件传输
最近因为要学习Python,于是把放在家里接了一年灰的树莓派又给搜出来了,刚买那会也捣鼓了好一阵子, 基本操作都学会了,但现在又忘光了,只能又从头开始搞了,首先第一个要解决的是怎么把文件从电脑传输到树 ...
- struct与class的区别
C++中的struct是对C中struct的扩充,它已经不再只是一个包含不同数据类型的数据结构,因为其扩充了太多功能.总的来说,C++中struct和class极其相似,比如,struct能包含成员函 ...
- Spark入门到精通--(第八节)环境搭建(Hadoop搭建)
上一节把Centos的集群免密码ssh登陆搭建完成,这一节主要讲一下Hadoop的环境搭建. Hadoop下载安装 下载官网的Hadoop 2.4.1的软件包.http://hadoop.apache ...
- Windows下安装使用python的Flask框架
1.安装python环境: 这里就不赘述了. 2.安装virtualenv虚拟环境: 这里使用使用第三方工具 virtualenv 创建虚拟环境.虚拟环境的好处如下(摘录网络): “ 安装 Flask ...