Flask 插件系列 - Flask-Mail

bcdxtfks 8年前發布 | 16K 次閱讀 Flask Python開發

簡介

給用戶發送郵件是 Web 應用中最常見的任務之一,比如用戶注冊,找回密碼等。Python 內置了一個 smtplib 的模塊,可以用來發送郵件,這里我們使用 Flask-Mail ,是因為它可以和 Flask 集成,讓我們更方便地實現此功能。

安裝

使用 pip 安裝:

$ pip install Flask-Mail

或下載源碼安裝:

$ 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 郵箱的服務器地址和端口是什么。

# -- 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)</code></pre>

在發送前,需要先設置用戶名和密碼,當然你也可以直接寫在文件里,如果是從環境變量讀取,可以這么做:

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

將上面的 sender 和 recipients 改一下,就可以進行測試了。

從上面的代碼,我們可以知道,使用 Flask-Mail 發送郵件主要有以下幾個步驟:

  • 配置 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)</code></pre>

在上面,我們創建了一個線程,執行的任務是 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)</code></pre>

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

批量發送

在某些情況下,我們需要批量發送郵件,比如給網站的所有注冊用戶發送改密碼的郵件,這時為了避免每次發郵件時都要創建和關閉跟服務器的連接,我們的代碼需要做一些調整,類似如下:

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 任務隊列等。

 

 

來自:https://segmentfault.com/a/1190000007378073

 

 本文由用戶 bcdxtfks 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!