Flask 插件系列 - Flask-Mail

前往本文博客html

簡介

給用戶發送郵件是 Web 應用中最多見的任務之一,好比用戶註冊,找回密碼等。Python 內置了一個 smtplib 的模塊,能夠用來發送郵件,這裏咱們使用 Flask-Mail,是由於它能夠和 Flask 集成,讓咱們更方便地實現此功能。python

安裝

使用 pip 安裝:git

$ pip install Flask-Mail

或下載源碼安裝:github

$ git clone https://github.com/mattupstate/flask-mail.git
$ cd flask-mail
$ python setup.py install

發送郵件

Flask-Mail 鏈接到簡單郵件傳輸協議 (Simple Mail Transfer Protocol, SMTP) 服務器,並把郵件交給這個服務器發送。這裏以 QQ 郵箱爲例,介紹如何簡單地發送郵件。在此以前,咱們須要知道 QQ 郵箱的服務器地址和端口是什麼,點此查看flask

# -*- coding: utf-8 -*-

from flask import Flask
from flask_mail import Mail, Message
import os

app = Flask(__name__)

app.config['MAIL_SERVER'] = 'smtp.qq.com'  # 郵件服務器地址
app.config['MAIL_PORT'] = 25               # 郵件服務器端口
app.config['MAIL_USE_TLS'] = True          # 啓用 TLS
app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME') or 'me@example.com'
app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD') or '123456'

mail = Mail(app)

@app.route('/')
def index():
    msg = Message('Hi', sender='me@example.com', recipients=['he@example.com'])
    msg.html = '<b>Hello Web</b>'
    # msg.body = 'The first email!'
    mail.send(msg)
    return '<h1>OK!</h1>'

if __name__ == '__main__':
    app.run(host='127.0.0.1', debug=True)

在發送前,須要先設置用戶名和密碼,固然你也能夠直接寫在文件裏,若是是從環境變量讀取,能夠這麼作:api

$ export MAIL_USERNAME='me@example.com'
$ export MAIL_PASSWORD='123456'

將上面的 senderrecipients 改一下,就能夠進行測試了。安全

從上面的代碼,咱們能夠知道,使用 Flask-Mail 發送郵件主要有如下幾個步驟:服務器

  • 配置 app 對象的郵件服務器地址,端口,用戶名和密碼等app

  • 建立一個 Mail 的實例:mail = Mail(app)異步

  • 建立一個 Message 消息實例,有三個參數:郵件標題、發送者和接收者

  • 建立郵件內容,若是是 HTML 格式,則使用 msg.html,若是是純文本格式,則使用 msg.body

  • 最後調用 mail.send(msg) 發送消息

Flask-Mail 配置項

Flask-Mail 使用標準的 Flask 配置 API 進行配置,下面是一些經常使用的配置項:

配置項 說明
MAIL_SERVER 郵件服務器地址,默認爲 localhost
MAIL_PORT 郵件服務器端口,默認爲 25
MAIL_USE_TLS 是否啓用傳輸層安全 (Transport Layer Security, TLS)協議,默認爲 False
MAIL_USE_SSL 是否啓用安全套接層 (Secure Sockets Layer, SSL)協議,默認爲 False
MAIL_DEBUG 是否開啓 DEBUG,默認爲 app.debug
MAIL_USERNAME 郵件服務器用戶名,默認爲 None
MAIL_PASSWORD 郵件服務器密碼,默認爲 None
MAIL_DEFAULT_SENDER 郵件發件人,默認爲 None,也可在 Message 對象裏指定
MAIL_MAX_EMAILS 郵件批量發送個數上限,默認爲 None
MAIL_SUPPRESS_SEND 默認爲 app.testing,若是爲 True,則不會真的發送郵件,供測試用

異步發送郵件

使用上面的方式發送郵件,會發現頁面卡頓了幾秒纔出現消息,這是由於咱們使用了同步的方式。爲了不發送郵件過程當中出現的延遲,咱們把發送郵件的任務移到後臺線程中,代碼以下:

# -*- coding: utf-8 -*-

from flask import Flask
from flask_mail import Mail, Message
from threading import Thread
import os

app = Flask(__name__)

app.config['MAIL_SERVER'] = 'smtp.qq.com'
app.config['MAIL_PORT'] = 25
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME') or 'smtp.example.com'
app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD') or '123456'

mail = Mail(app)

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

@app.route('/sync')
def send_email():
    msg = Message('Hi', sender='me@example.com', recipients=['he@example.com'])
    msg.html = '<b>send email asynchronously</b>'

    thr = Thread(target=send_async_email, args=[app, msg])
    thr.start()
    return 'send successfully'

if __name__ == '__main__':
    app.run(host='127.0.0.1', debug=True)

在上面,咱們建立了一個線程,執行的任務是send_async_email,該任務的實現涉及一個問題1

不少 Flask 擴展都假設已經存在激活的程序上下文和請求上下文。Flask-Mail 中的 send() 函數使用 current_app,所以必須激活程序上下文。不過,在不一樣線程中執行 mail.send() 函數時,程序上下文要使用 app.app_context()人工建立。

帶附件的郵件

有時候,咱們發郵件的時候須要添加附件,好比文檔和圖片等,這也很簡單,代碼以下:

# -*- coding: utf-8 -*-

from flask import Flask
from flask_mail import Mail, Message
import os

app = Flask(__name__)

app.config['MAIL_SERVER'] = 'smtp.qq.com'  # 郵件服務器地址
app.config['MAIL_PORT'] = 25               # 郵件服務器端口
app.config['MAIL_USE_TLS'] = True          # 啓用 TLS
app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME') or 'me@example.com'
app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD') or '123456'

mail = Mail(app)

@app.route('/attach')
def add_attchments():
    msg = Message('Hi', sender='me@example.com', recipients=['other@example.com'])
    msg.html = '<b>Hello Web</b>'

    with app.open_resource("/Users/Admin/Documents/pixel-example.jpg") as fp:
        msg.attach("photo.jpg", "image/jpeg", fp.read())

    mail.send(msg)
    return '<h1>OK!</h1>'

if __name__ == '__main__':
    app.run(host='127.0.0.1', debug=True)

上面的代碼中,咱們經過 app.open_resource(path_of_attachment) 打開了本機的某張圖片,而後經過msg.attach() 方法將附件內容添加到 Message 對象。msg.attach() 方法的第一個參數是附件的文件名,第二個參數是文件內容的 MIME (Multipurpose Internet Mail Extensions) 類型,第三個參數是文件內容。

若是你不知道附件的 MIME 類型是什麼,能夠查看 MIME 參考手冊

批量發送

在某些狀況下,咱們須要批量發送郵件,好比給網站的全部註冊用戶發送改密碼的郵件,這時爲了不每次發郵件時都要建立和關閉跟服務器的鏈接,咱們的代碼須要作一些調整,相似以下:

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

上面的工做方式,使得應用與電子郵件服務器保持鏈接,一直到全部郵件已經發送完畢。某些郵件服務器會限制一次鏈接中的發送郵件的上限,這樣的話,你能夠配置 MAIL_MAX_EMAILS

須要注意的是,更好的發送大量電子郵件的方式是用專門的做業系統,好比用 Celery 任務隊列等。

本文完整的代碼在這裏

更多閱讀


  1. Flask Web Development
相關文章
相關標籤/搜索