Try   HackMD

Flask實作_ext_09_Flask-Mail_郵件發送

tags: flask flask_ext python mail

說明

flask-mail本身是將smtplib包裝起來的一個套件,這部份可以從flask-mail.py看的出來,搭配Flask應用對於我們派送註冊驗證信或警示訊息傳遞都非常實用。

安裝

pip install flask-mail

範例

import的模式跟其它擴展一樣都有兩種方式,實作的時候放入app,或是利用init_app,視你的使用情境來選用,如下兩個範例:

# 以此方式,所有的郵件設置會一次性渲染 from flask import Flask from flask-mail import Mail app = Flask(__name__) mail = Mail(app)
# 如果你有不同專案要走不同郵件設置的話,用此方式較佳 # 如果你使用工廠模式的話,也會以此方式來做初始化 from flask import Flask from flask-mail import Mail mail = Mail() app = Flask(__name__) mail.init_app(app)

如果你有使用github的習慣也請注意,flask-mail的參數設置或許會有隱密性資料,請記得使用環境變數來設置,如下(Windows範例)

set MAIL_USERNAME=<YOUR MAIL COUNT>
set MAIL_PASSWORD=<YOUR MAIL PASSWORD>

設置之後,就可以利用os.environ.get來取得環境變數,如此即可避免敏感資訊置於公開場合

app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME') 
app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD') 

範例:flask-mail 寄一封信

這次的範例使用的是hotmail做SMTP Server,如果你使用的是公司內部的Mail Server或是Gmail,再依實際情況調整設置即可,如下範例:

# file name:test_flask-mail.py from flask import Flask from flask_mail import Mail from flask_mail import Message app = Flask(__name__) app.config.update( # hotmail的設置 MAIL_SERVER='smtp.live.com', MAIL_PROT=587, MAIL_USE_TLS=True, MAIL_USERNAME='Your Hotmail Count', MAIL_PASSWORD='Your Hotmail Password' ) # 記得先設置參數再做實作mail mail = Mail(app) @app.route("/message") def index(): # 主旨 msg_title = 'Hello It is Flask-Mail' # 寄件者,若參數有設置就不需再另外設置 msg_sender = 'Sender Mail@mail_domain.com' # 收件者,格式為list,否則報錯 msg_recipients = ['Recipients@mail_domain.com'] # 郵件內容 msg_body = 'Hey, I am mail body!' # 也可以使用html # msg_html = '<h1>Hey,Flask-mail Can Use HTML</h1>' msg = Message(msg_title, sender=msg_sender, recipients=msg_recipients) msg.body = msg_body # msg.html = msg_html # mail.send:寄出郵件 mail.send(msg) return 'You Send Mail by Flask-Mail Success!!' if __name__ == "__main__": app.debug = True app.run()

相關的說明皆寫於註解,設置完畢之後就可以執行專案測試,輸入網址http://127.0.0.1:5000/message,得到訊息如下:

現在可以開啟郵箱來確認是否收到信件,如下:

flask-mail中有三個class分別為Mail,Message,Connection,這部份最好的理解方式就是看一次官方文件說明。

Message是實作郵件內容的類別,除了可以以文字做內容之外,也可以利用Html,這代表我們可以利用jinja2的樣板來做渲染,也可以透過attach實作夾帶附件。(下面有簡單說明)

另外,不同於操作smtplib需要做connect,在實作Mail.send的時候flask-mail會幫我們處理這部份的作業。

非同步寄送郵件

參考來源請見文章開頭連結

使用非同步的主因在於不希望使用者在按下發送信件按鈕之後需要浪費時間等待寄送信件的程序,這個等待時間會造成使用者體驗不佳,而且使用者也不需要浪費時間等待,因此利用多執行緒將使用者點擊按鈕之後的信件派送程序切割,如下範例:

# file name:test_flask-mail.py from flask import Flask from flask_mail import Mail from flask_mail import Message # 加入threating from threading import Thread app = Flask(__name__) app.config.update( # hotmail的設置 MAIL_SERVER='smtp.live.com', MAIL_PROT=587, MAIL_USE_TLS=True, MAIL_USERNAME='Your Hotmail Count', MAIL_PASSWORD='Your Hotmail Password' ) # 記得先設置參數再做實作mail mail = Mail(app) @app.route("/message") def index(): # 主旨 msg_title = 'Hello It is Flask-Mail' # 寄件者,若參數有設置就不需再另外設置 msg_sender = 'Sender Mail@mail_domain.com' # 收件者,格式為list,否則報錯 msg_recipients = ['Recipients@mail_domain.com'] # 郵件內容 # msg_body = 'Hey, I am mail body!' # 也可以利用html做內容 msg_html = '<h1>Hey,Flask-mail Can Use HTML, and I Use thread</h1>' msg = Message(msg_title, sender=msg_sender, recipients=msg_recipients) # msg.body = msg_body msg.html = msg_html # 使用多線程 thr = Thread(target=send_async_email, args=[app, msg]) thr.start() return 'You Send Mail by Flask-Mail Success!!' def send_async_email(app, msg): # 下面有說明 with app.app_context(): mail.send(msg) if __name__ == "__main__": app.debug = True app.run()

第44行:你必需讓程序是在相同的Context內,因此需要也必需利用app.app_context來確保線程。

這個範例我用Html做郵件內容的渲染,如下:

threading的部份不在此節的範圍,不多說,我們看send_async_email這個function。我們取得了appmsg兩個物件之後,利用了app.app_context來讓整個程序是在一個程序的上下文內,這是flask-mail中的send的限制。

雖然兩個物件都是從context中傳來的,但是因為我們開了另一個新的thread,所以必需手動將物件放入一個程序上下文中。

調整為非同步模式,執行專案會發現流暢許多,網頁不會有停頓的感覺,整個使用者的體驗是可以有效提高的,因為使用者不需要再等待信件派送的程序。

如果你拿掉了with app.app_context的話,會有以下錯誤說明:

This typically means that you attempted to use functionality that needed
to interface with the current application object in a way.  To solve
this set up an application context with app.app_context().  See the
documentation for more information.

總結

這一話我們討論了flask-mail的應用以及非同步對使用者體驗的改善,在非同步的部份如果相進一步的瞭解,會建議可以搭配Celery來使用,值得學習,另外我們將測試使用jinja2來實作版面,不要忘了繼續學習。

Flask-Mail_利用模板渲染:Flask實作_ext_10_Flask-Mail_利用模板渲染

參數

配置說明

部份配合原始碼看一下比較能夠理解,如下圖說明:

  • MAIL_SERVER : 預設為localhost
    SMTP的主機位置
  • MAIL_PORT : 預設為 25
    SMTP的PORT
  • MAIL_USE_TLS : 預設為 False
    是否使用TLS
  • MAIL_USE_SSL : 預設為 False
    是否使用SSL
  • MAIL_DEBUG : 預設為 app.debug
    是否啟用DEBUG模式
    預設會使用flask的debug設置
  • MAIL_USERNAME : 預設為 None
    登入mail server的帳號
  • MAIL_PASSWORD : 預設為 None
    登入mail server的密碼
  • MAIL_DEFAULT_SENDER : 預設為 None
    預設郵件寄件人,設置之後,在實作message的時候若沒有設置就以此為主。
  • MAIL_MAX_EMAILS : 預設為 None
    一次連接的郵件最大發送數,不過基本上大量郵件的話會採不同的方式來處理。
    像多線程或丟另一個程序處理,否則會造成發送郵件時卡住。
  • MAIL_SUPPRESS_SEND : 預設為 app.testing
    設置True的時候可以限制發送郵件
    在開發測試的時候,實作send()時就不會真的發送郵件。
  • MAIL_ASCII_ATTACHMENTS : 預設為 False
    將編碼格式轉為ASCII

Message

class flask_mail.Message(subject='', recipients=None, body=None, html=None, sender=None, cc=None, bcc=None, attachments=None, reply_to=None, date=None, charset=None, extra_headers=None, mail_options=None, rcpt_options=None)
  • Parameters:
    • subject – email subject header郵件主旨
    • recipients – list of email addresses收件人,格式需為list,可利用add_recipient加入
    • body – plain text message郵件文字內容
    • html – HTML message郵件html內容
    • sender – email sender address, or MAIL_DEFAULT_SENDER by default寄件人
    • cc – CC list副件人員,格式需為list
    • bcc – BCC list密件,格式需為list
    • attachments – list of Attachment instances附件,可利用attach()加入
    • reply_to – reply-to address待測
    • date – send date寄件日期
    • charset – message character set郵件編碼
    • extra_headers – A dictionary of additional headers for the message待測
    • mail_options – A list of ESMTP options to be used in MAIL FROM command待測
    • rcpt_options – A list of ESMTP options to be used in RCPT commands待測
  • method:
    • add_recipient(recipient):增加收件人
    ​​​​self.recipients.append(recipient)
    • attach(filename=None, content_type=None, data=None, disposition=None, headers=None):增加附件
    ​​​​self.attachments.append( ​​​​ Attachment(filename, content_type, data, disposition, headers))

常用配置

hotmail

MAIL_SERVER='smtp.live.com',
MAIL_PROT=587,
MAIL_USE_TLS=True,
MAIL_USERNAME='Your Hotmail Count',
MAIL_PASSWORD='Your Hotmail Password'

gmail

使用gmail記得要先申請低安全性應用程式的密碼,可以產生一組跟你的密碼不同的密碼,不過如果你有申請兩段式登入認證的話,就不能用了!

MAIL_SERVER='smtp.gmail.com',
MAIL_PROT=465,
MAIL_USE_SSL=True,
MAIL_USERNAME='Your Gmail Count',
MAIL_PASSWORD='Your Gmail Password'

其它smtp測試

如果覺得使用其它smtp測試很麻煩的話,可以試著自己建置一個測試用的smtp。
只是個人透過此方法沒有成功過,我另外寫一個利用smtplib直接寄可以成功,利用telnet去測也正常,但是透過flask-mail一直出現錯誤訊息(目標電腦拒絕連線 10061),如果有成功的前輩再指導。

import smtpd
import asyncore

server = smtpd.DebuggingServer(('127.0.0.1', 1025), None)

asyncore.loop()