1. 程式人生 > >使用Flask-Mail和qq郵箱SMTP服務傳送郵件

使用Flask-Mail和qq郵箱SMTP服務傳送郵件

專案中不可避免需要使用郵箱認證,如果使用flask則可以利用Flask-Mail來實現。

Flask-Mail 擴充套件提供了一個簡單的介面,可以在 Flask 應用中設定 SMTP 使得可以在檢視以及指令碼中傳送郵件資訊。

開啟qq郵箱SMTP服務

這裡我利用的qq郵箱的SMTP服務,所以首先需要先開啟該服務並獲得授權碼。在qq郵箱 “郵箱設定 — 賬戶”裡找到下圖位置,開啟SMTP服務。
開啟STMP服務
之後手機驗證什麼的依自己帳號設定,驗證成功後會獲得一個授權碼,這個需要儲存後續傳送郵箱時密碼就填這個授權碼。

安裝Flask-Mail

pip install Flask-Mail

配置Flask-Mail

配置項 預設值 功能
MAIL_SERVER localhost 郵箱伺服器
MAIL_PORT 25
MAIL_USE_TLS False 是否使用TLS
MAIL_USE_SSL False 是否使用SSL
MAIL_DEBUG app.debug 是否為DEBUG模式,列印除錯訊息
MAIL_SUPPRESS_SEND app.testing 設定是否真的傳送郵件,True不傳送
MAIL_USERNAME None 使用者名稱,填郵箱
MAIL_PASSWORD None 密碼,填授權碼
MAIL_DEFAULT_SENDER None 預設傳送者,填郵箱
MAIL_MAX_EMAILS None 一次連線中的傳送郵件的上限
MAIL_ASCII_ATTACHMENTS False 如果 MAIL_ASCII_ATTACHMENTS 設定成 True 的話,檔名將會轉換成 ASCII 的。一般用於新增附件。

郵件是通過一個 Mail 例項進行管理:

from flask import Flask
from flask_mail import Mail

app = Flask(__name__)
# ...
app.config['MAIL_SERVER'] = 'smtp.qq.com' app.config['MAIL_PORT'] = 465 app.config['MAIL_USE_SSL'] = True app.config['MAIL_USE_TLS'] = False app.config['MAIL_USERNAME'] = '[email protected]' app.config['MAIL_PASSWORD'] = '填授權碼' # ... mail = Mail(app)

在這個例子中所有的郵件將會使用傳入到 Mail 例項中的應用程式的配置項進行傳送。

或者你也可以在應用程式配置的時候設定你的 Mail 例項,通過使用 init_app 方法:

mail = Mail()

app = Flask(__name__)
# ...
app.config['MAIL_SERVER'] = 'smtp.qq.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USE_SSL'] = True
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USERNAME'] = '[email protected]'
app.config['MAIL_PASSWORD'] = '填授權碼'
# ...
mail.init_app(app)

在這個例子中郵件將會使用 Flask 的 current_app 中的配置項進行傳送。如果你有多個具有不用配置項的多個應用執行在同一程式的時候,這種設定方式是十分有用的,

傳送郵件

首先要建立傳送郵件的內容Message例項:

from flask_mail import Message
msg = Message(subject="Hello World!",
              sender="[email protected]",
              recipients=["[email protected]"])

其中,
subject為郵件標題。
sender為傳送方,如果你設定了 “MAIL_DEFAULT_SENDER”,就不必再次填寫發件人,預設情況下將會使用配置項的發件人。
recipients為接收方,可以設定一個或者多個收件人,也可以後續再新增。

msg.recipients = ["xxx@qq.com"]
msg.add_recipient("xxxx@qq.com")

如果 sender 是一個二元組,它將會被分成姓名和郵件地址:

msg = Message("Hello",
              sender=("Me", "[email protected]"))

郵件內容可以包含主體以及/或者 HTML:

msg.body = "testing"
msg.html = "<b>testing</b>"

最後,傳送郵件的時候請使用 Flask 應用設定的 Mail 例項:

mail.send(msg)

大量郵件

通常在一個 Web 應用中每一個請求會同時傳送一封或者兩封郵件。在某些特定的場景下,有可能會發送數十或者數百封郵件,不過這種傳送工作會給交離線任務或者指令碼執行。

在這種情況下發送郵件的程式碼會有些不同:

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

        conn.send(msg)

與電子郵件伺服器的連線會一直保持活動狀態直到所有的郵件都已經發送完成後才會關閉(斷開)。

有些郵件伺服器會限制一次連線中的傳送郵件的上限。你可以設定重連前的傳送郵件的最大數,通過配置 MAIL_MAX_EMAILS 。

附件

在郵件中新增附件同樣非常簡單:

with app.open_resource("image.png") as fp:
    msg.attach("image.png", "image/png", fp.read())

如果 MAIL_ASCII_ATTACHMENTS 設定成 True 的話,檔名將會轉換成 ASCII 的。 當檔名是以 UTF-8 編碼的時候,使用郵件轉發的時候會修改郵件內容並且混淆 Content-Disposition 描述,這個時候 MAIL_ASCII_ATTACHMENTS 配置項是十分有用的。轉換成 ASCII 的基本方式就是對 non-ASCII 字元的去除。任何一個 unicode 字元能夠被 NFKD 分解成一個或者多個 ASCII 字元。

完整例子

假設你已經開啟了qq郵箱的STMP服務以及配置好flask和flask-mail環境。

# -*- coding: utf-8 -*-
from flask import Flask, request
from flask_script import Manager, Shell
from flask_mail import Mail, Message
from threading import Thread


app = Flask(__name__)
app.config['MAIL_DEBUG'] = True             # 開啟debug,便於除錯看資訊
app.config['MAIL_SUPPRESS_SEND'] = False    # 傳送郵件,為True則不傳送
app.config['MAIL_SERVER'] = 'smtp.qq.com'   # 郵箱伺服器
app.config['MAIL_PORT'] = 465               # 埠
app.config['MAIL_USE_SSL'] = True           # 重要,qq郵箱需要使用SSL
app.config['MAIL_USE_TLS'] = False          # 不需要使用TLS
app.config['MAIL_USERNAME'] = '[email protected]'  # 填郵箱
app.config['MAIL_PASSWORD'] = 'xxxxxx'      # 填授權碼
app.config['MAIL_DEFAULT_SENDER'] = '[email protected]'  # 填郵箱,預設傳送者
manager = Manager(app)
mail = Mail(app)


# 非同步傳送郵件
def send_async_email(app, msg):
    with app.app_context():
        mail.send(msg)


@app.route('/')
def index():
    msg = Message(subject='Hello World',
                  sender="[email protected]",  # 需要使用預設傳送者則不用填
                  recipients=['[email protected]', '[email protected]'])
    # 郵件內容會以文字和html兩種格式呈現,而你能看到哪種格式取決於你的郵件客戶端。
    msg.body = 'sended by flask-email'
    msg.html = '<b>測試Flask傳送郵件<b>'
    thread = Thread(target=send_async_email, args=[app, msg])
    thread.start()
    return '<h1>郵件傳送成功</h1>'


if __name__ == '__main__':
    manager.run()

tip:具體工程中,配置可以寫在單獨一個檔案如”.env”,然後利用python-envcfg來讀取配置,如:
app.config.from_object(‘envcfg.raw’)