使用 Flask-Mail 和 qq 邮箱 SMTP 服务发送邮件

3,980 阅读4分钟
原文链接: blog.csdn.net

项目中不可避免需要使用邮箱认证,如果使用flask则可以利用Flask-Mail来实现。

Flask-Mail 扩展提供了一个简单的接口,可以在 Flask 应用中设置 SMTP 使得可以在视图以及脚本中发送邮件信息。

开启qq邮箱SMTP服务

这里我利用的qq邮箱的SMTP服务,所以首先需要先开启该服务并获得授权码。在qq邮箱 “邮箱设置 — 账户”里找到下图位置,开启SMTP服务。
开启STMP服务
之后手机验证什么的依自己帐号设置,验证成功后会获得一个授权码,这个需要保存后续发送邮箱时密码就填这个授权码。

安装Flask-Mail

pip install Flask-Mail

配置Flask-Mail

配置项 默认值 功能
MAIL_SERVER localhost 邮箱服务器
MAIL_PORT 25 端口
MAIL_USE_TLS False 是否使用TLS
MAIL_USE_SSL False 是否使用SSL
MAIL_DEBUG app.debug 是否为DEBUG模式,打印调试消息
MAIL_SUPPRESS_SEND app.testing 设置是否真的发送邮件,True不发送
MAIL_USERNAME None 用户名,填邮箱
MAIL_PASSWORD None 密码,填授权码
MAIL_DEFAULT_SENDER None 默认发送者,填邮箱
MAIL_MAX_EMAILS None 一次连接中的发送邮件的上限
MAIL_ASCII_ATTACHMENTS False 如果 MAIL_ASCII_ATTACHMENTS 设置成 True 的话,文件名将会转换成 ASCII 的。一般用于添加附件。

邮件是通过一个 Mail 实例进行管理:

from flask import Flask
from flask_mail import Mail

app = Flask(__name__)
# ...
app.config['MAIL_SERVER'] = 'smtp.qq.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USE_SSL'] = True
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USERNAME'] = 'XXX@qq.com'
app.config['MAIL_PASSWORD'] = '填授权码'
# ...
mail = Mail(app)

在这个例子中所有的邮件将会使用传入到 Mail 实例中的应用程序的配置项进行发送。

或者你也可以在应用程序配置的时候设置你的 Mail 实例,通过使用 init_app 方法:

mail = Mail()

app = Flask(__name__)
# ...
app.config['MAIL_SERVER'] = 'smtp.qq.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USE_SSL'] = True
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USERNAME'] = 'XXX@qq.com'
app.config['MAIL_PASSWORD'] = '填授权码'
# ...
mail.init_app(app)

在这个例子中邮件将会使用 Flask 的 current_app 中的配置项进行发送。如果你有多个具有不用配置项的多个应用运行在同一程序的时候,这种设置方式是十分有用的,

发送邮件

首先要创建发送邮件的内容Message实例:

from flask_mail import Message
msg = Message(subject="Hello World!",
              sender="from@qq.com",
              recipients=["to@example.com"])

其中,
subject为邮件标题。
sender为发送方,如果你设置了 “MAIL_DEFAULT_SENDER”,就不必再次填写发件人,默认情况下将会使用配置项的发件人。
recipients为接收方,可以设置一个或者多个收件人,也可以后续再添加。

msg.recipients = ["xxx@qq.com"]
msg.add_recipient("xxxx@qq.com")

如果 sender 是一个二元组,它将会被分成姓名和邮件地址:

msg = Message("Hello",
              sender=("Me", "me@example.com"))

邮件内容可以包含主体以及/或者 HTML:

msg.body = "testing"
msg.html = "<b>testing</b>"

最后,发送邮件的时候请使用 Flask 应用设置的 Mail 实例:

mail.send(msg)

大量邮件

通常在一个 Web 应用中每一个请求会同时发送一封或者两封邮件。在某些特定的场景下,有可能会发送数十或者数百封邮件,不过这种发送工作会给交离线任务或者脚本执行。

在这种情况下发送邮件的代码会有些不同:

with mail.connect() as conn:
    for user in users:
        message = '...'
        subject = "hello, %s" % user.name
        msg = Message(recipients=[user.email],
                      body=message,
                      subject=subject)

        conn.send(msg)

与电子邮件服务器的连接会一直保持活动状态直到所有的邮件都已经发送完成后才会关闭(断开)。

有些邮件服务器会限制一次连接中的发送邮件的上限。你可以设置重连前的发送邮件的最大数,通过配置 MAIL_MAX_EMAILS 。

附件

在邮件中添加附件同样非常简单:

with app.open_resource("image.png") as fp:
    msg.attach("image.png", "image/png", fp.read())

如果 MAIL_ASCII_ATTACHMENTS 设置成 True 的话,文件名将会转换成 ASCII 的。 当文件名是以 UTF-8 编码的时候,使用邮件转发的时候会修改邮件内容并且混淆 Content-Disposition 描述,这个时候 MAIL_ASCII_ATTACHMENTS 配置项是十分有用的。转换成 ASCII 的基本方式就是对 non-ASCII 字符的去除。任何一个 unicode 字符能够被 NFKD 分解成一个或者多个 ASCII 字符。

完整例子

假设你已经开启了qq邮箱的STMP服务以及配置好flask和flask-mail环境。

# -*- coding: utf-8 -*-
from flask import Flask, request
from flask_script import Manager, Shell
from flask_mail import Mail, Message
from threading import Thread


app = Flask(__name__)
app.config['MAIL_DEBUG'] = True             # 开启debug,便于调试看信息
app.config['MAIL_SUPPRESS_SEND'] = False    # 发送邮件,为True则不发送
app.config['MAIL_SERVER'] = 'smtp.qq.com'   # 邮箱服务器
app.config['MAIL_PORT'] = 465               # 端口
app.config['MAIL_USE_SSL'] = True           # 重要,qq邮箱需要使用SSL
app.config['MAIL_USE_TLS'] = False          # 不需要使用TLS
app.config['MAIL_USERNAME'] = 'xxx@qq.com'  # 填邮箱
app.config['MAIL_PASSWORD'] = 'xxxxxx'      # 填授权码
app.config['MAIL_DEFAULT_SENDER'] = 'xxx@qq.com'  # 填邮箱,默认发送者
manager = Manager(app)
mail = Mail(app)


# 异步发送邮件
def send_async_email(app, msg):
    with app.app_context():
        mail.send(msg)


@app.route('/')
def index():
    msg = Message(subject='Hello World',
                  sender="xxx@qq.com",  # 需要使用默认发送者则不用填
                  recipients=['x1@qq.com', 'x2@qq.com'])
    # 邮件内容会以文本和html两种格式呈现,而你能看到哪种格式取决于你的邮件客户端。
    msg.body = 'sended by flask-email'
    msg.html = '<b>测试Flask发送邮件<b>'
    thread = Thread(target=send_async_email, args=[app, msg])
    thread.start()
    return '<h1>邮件发送成功</h1>'


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

tip:具体工程中,配置可以写在单独一个文件如”.env”,然后利用Python-envcfg来读取配置,如:
app.config.from_object(‘envcfg.raw’)


参考:
flask-email手册