我们可以使用 python 的smtplib库,但是使用集成的flask-mail更方便

Basic

安装

(venv) $ pip install flask-mail

配置

Key Default Description
MAIL_HOSTNAME localhost Hostname or IP address of the email server
MAIL_PORT 25 Port of the email server
MAIL_USE_TLS False Enable Transport Layer Security (TLS) security
MAIL_USE_SSL False Enable Secure Sockets Layer (SSL) security
MAIL_USERNAME None Mail account username
MAIL_PASSWORD None Mail account password
import os
# ...
app.config['MAIL_SERVER'] = 'smtp.googlemail.com'
app.config['MAIL_PORT'] = 587
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME')
app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD')

邮箱的用户名和密码属于敏感信息,最好不要直接写在代码中,而是定义在环境变量中
(主流邮箱的配置)

# Linux or Mac OS
(venv) $ export MAIL_USERNAME=username@gmail.com
(venv) $ export MAIL_PASSWORD=gmailPassword
# Windows
(venv) $ set MAIL_USERNAME=username@gmail.com
(venv) $ set MAIL_PASSWORD=gmailPassword

在虚拟环境中创建的环境变量只存在于虚拟环境中, 当退出虚拟环境后则无法获取在虚拟环境中定义的环境变量

Sending Email from the Python Shell

(venv) $ python hello.py shell
>>> from flask.ext.mail import Message
>>> from hello import mail
>>> msg = Message('test subject', sender='you@example.com',
... recipients=['you@example.com'])
>>> msg.body = 'text body'
>>> msg.html = '<b>HTML</b> body'
>>> with app.app_context():
... mail.send(msg)

Integrating Emails with the Application

定义send_email函数

from flask.ext.mail import Message

app.config['FLASKY_MAIL_SUBJECT_PREFIX'] = '[Flasky]'
app.config['FLASKY_MAIL_SENDER'] = 'Flasky Admin <flasky@example.com>'

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)
    mail.send(msg)

使用

# ...
app.config['FLASKY_ADMIN'] = os.environ.get('FLASKY_ADMIN')
# ...
@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))

异步发送邮件

发送邮件可能会耗费一些时间,为了用户界面的流畅性,可以在后台另起线程发送

from threading import Thread

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

flask-mailsned()函数current_app,所以需要app_context

with app.app_context():
    mail.send(msg)