電子郵件是最經常使用的通訊方式之一。雖然Python標準庫中的smtplib包可用在Flask程序中發送電子郵件,但包裝了smtplib的Flask-Mail擴展能更好的和Flask集成。html
1.1使用pip安裝python
pip install flask-mail
1.2 下載源碼安裝git
git clone https://github.com/mattupstate/flask-mail.git cd flask-mail python setup.py install
from flask import Flask from flask_mail import Mail, Message app = Flask(__name__) mail = Mail(app)
3.1 Flask-Mail經常使用配置項github
Flask-Mail經過標準的Flask配置API進行配置,這些經常使用的配置項以下:flask
配置 | 默認值 | 說明 |
MAIL_SERVER | localhost | 電子郵件服務器的主機名或IP地址 |
MAIL_PORT | 25 | 電子郵件服務器的端口 |
MAIL_USE_TLS | False | 啓用傳輸層安全(Transport Layer Security,TLS)協議 |
MAIL_USE_SSL | Flase | 啓用安全套接層(Secure Sockets Layer,SSL)協議 |
MAIL_USERNAME | None | 郵件帳戶的用戶名 |
MAIL_PASSWORD | None | 郵件帳戶的密碼 |
MAIL_DEFAULT_SENDER | None | 默認發件人,若是Message對象裏沒指定發件人,就採用默認發件人 |
MAIL_MAX_EMAILS | None | 郵件批量發送個數上限,默認爲沒有上限 |
MAIL_SUPPRESS_SEND | app.testing | 調用「Mail.send()」方法後,郵件不會真的被髮送,在測試環境中使用,默認爲False |
MAIL_ASCII_ATTACHMENTS | Flase | 將附件的文件名強制轉換爲ASCII字符,避免在某些狀況下出現亂碼 |
3.2 常見的SMTP郵箱服務配置安全
(1)配置QQ郵箱服務器服務器
MAIL_SERVER = 'smtp.qq.com', MAIL_PROT = 25, MAIL_USE_TLS = True, MAIL_USE_SSL = False, MAIL_USERNAME = "", MAIL_PASSWORD = "",
QQ郵箱的配置方式以下:app
開啓了受權以後,就會彈出生成受權碼頁面:異步
注意:async
a.qq郵箱的服務器地址爲smtp.qq.com;
b.郵箱服務的端口爲25或者465均可以;
c.TLS,SSL的選擇不少人發不出去郵件的關鍵之一,這裏QQ郵箱選擇TLS;
d.帳號和密碼須要特別注意,這裏的帳號是本身的QQ郵箱帳號,密碼不是QQ郵箱密碼,而是生成的受權碼;
(2)其餘郵箱後續補充
下面舉例說明flask-email擴展是如何實現簡單郵件發送的:
from flask import Flask from flask_mail import Mail, Message
app = Flask(__name__) app.config.update( MAIL_SERVER='smtp.qq.com', MAIL_PROT=465, MAIL_USE_TLS=True, MAIL_USE_SSL=False, MAIL_USERNAME="xxxxxxxxxxxxx@qq.com", MAIL_PASSWORD="****************", ) mail = Mail(app) @app.route('/') def index(): # sender 發送方,recipients 郵件接收方列表 msg = Message("Hi!This is a test ",sender='xxxxxxxxxxxxxx@qq.com', recipients=['test@example.com']) # msg.body 郵件正文 msg.body = "This is a first email" mail.send(msg) print("Mail sent") return 'send successfully'
if __name__ == "__main__": app.run(debug=True)
若是想發送信息,首先須要建立一個Message實例:
msg = Message("Hello",sender="from@example.com",recipients=["to@example.com"])
固然,咱們也能夠單獨添加郵件接收對象:
msg.recipients = ["you@example.com"] msg.add_recipient("somebodyelse@example.com")
在配置參數的時候,若是咱們設置了MAIL_DEFAULT_SENDER參數,在後面建立message實例時不須要清楚指明郵件發送方,此時程序會自動獲取默認配置:
msg = Message("Hello",recipients=["to@example.com"])
使用上面的方式發送郵件,會發現頁面卡頓了幾秒纔出現消息,這是由於咱們使用了同步的方式。爲了不發送郵件過程當中出現的延遲,咱們把發送郵件的任務移到後臺線程中。代碼以下:
# -*- 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 'xxxxxxxxxx@qq.com' app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD') or '*********' 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='xxxxxxxx@qq.com', recipients=['test@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(debug=True)
在上面,咱們建立了一個線程,執行的任務是send_async_email
,該任務的實現涉及一個問題:
不少 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 app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME') or 'xxxxxxxxx@qq.com' app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD') or '**********' mail = Mail(app) @app.route('/attach') def add_attchments(): msg = Message('A photo', sender='xxxxxxxxx@qq.com', recipients=['ltest@example.com']) msg.html = '<b>A beautiful photo!</b>' with app.open_resource("1111.jpg") as fp: msg.attach("photo.jpg", "image/jpeg", fp.read()) mail.send(msg) return '<h1>OK!</h1>' if __name__ == '__main__': app.run(debug=True)
上面的代碼中,咱們經過 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
。