# flask-mail
在 Web 應用中的一個最基本的功能就是能夠給用戶發送郵件。
**Flask-Mail** 擴展提供了一個簡單的接口,可以在 [Flask](http://flask.pocoo.org) 應用中設置 SMTP 使得可以在視圖以及腳本中發送郵件信息。
## 鏈接
* [原版文檔](http://packages.python.org/Flask-Mail/)
* [源代碼](http://github.com/mattupstate/flask-mail)
* [_更新歷史_](changelog.html)
## 安裝 Flask-Mail
使用 **pip** 或者 **easy_install** 安裝 Flask-Mail:
```
pip install Flask-Mail
```
或者從版本控制系統(github)中下載最新的版本:
```
git clone https://github.com/mattupstate/flask-mail.git
cd flask-mail
python setup.py install
```
如果你正在使用 **virtualenv**,假設你會安裝 flask-mail 在運行你的 Flask 應用程序的同一個 virtualenv 上。
## 配置 Flask-Mail
**Flask-Mail** 使用標準的 Flask 配置 API 進行配置。下面這些是可用的配置型(每一個將會在文檔中進行解釋):
* **MAIL_SERVER** : 默認為 **‘localhost’**
* **MAIL_PORT** : 默認為 **25**
* **MAIL_USE_TLS** : 默認為 **False**
* **MAIL_USE_SSL** : 默認為 **False**
* **MAIL_DEBUG** : 默認為 **app.debug**
* **MAIL_USERNAME** : 默認為 **None**
* **MAIL_PASSWORD** : 默認為 **None**
* **MAIL_DEFAULT_SENDER** : 默認為 **None**
* **MAIL_MAX_EMAILS** : 默認為 **None**
* **MAIL_SUPPRESS_SEND** : 默認為 **app.testing**
* **MAIL_ASCII_ATTACHMENTS** : 默認為 **False**
另外,**Flask-Mail** 使用標準的 Flask 的 `TESTING` 配置項用于單元測試(下面會具體介紹)。
郵件是通過一個 `Mail` 實例進行管理:
```
from flask import Flask
from flask_mail import Mail
app = Flask(__name__)
mail = Mail(app)
```
在這個例子中所有的郵件將會使用傳入到 `Mail` 實例中的應用程序的配置項進行發送。
或者你也可以在應用程序配置的時候設置你的 `Mail` 實例,通過使用 **init_app** 方法:
```
mail = Mail()
app = Flask(__name__)
mail.init_app(app)
```
在這個例子中郵件將會使用 Flask 的 `current_app` 中的配置項進行發送。如果你有多個具有不用配置項的多個應用運行在同一程序的時候,這種設置方式是十分有用的,
## 發送郵件
為了能夠發送郵件,首先需要創建一個 `Message` 實例:
```
from flask_mail import Message
@app.route("/")
def index():
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`,就不必再次填寫發件人,默認情況下將會使用配置項的發件人:
```
msg = Message("Hello",
recipients=["to@example.com"])
```
如果 `sender` 是一個二元組,它將會被分成姓名和郵件地址:
```
msg = Message("Hello",
sender=("Me", "me@example.com"))
assert msg.sender == "Me <me@example.com>"
```
郵件內容可以包含主體以及/或者 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())
```
具體細節請參看 [API](#api) 。
如果 `MAIL_ASCII_ATTACHMENTS` 設置成 **True** 的話,文件名將會轉換成 ASCII 的。 當文件名是以 UTF-8 編碼的時候,使用郵件轉發的時候會修改郵件內容并且混淆 Content-Disposition 描述,這個時候 `MAIL_ASCII_ATTACHMENTS` 配置項是十分有用的。轉換成 ASCII 的基本方式就是對 non-ASCII 字符的去除。任何一個 unicode 字符能夠被 NFKD 分解成一個或者多個 ASCII 字符。
## 單元測試以及禁止發送郵件
當在單元測試中,或者在一個開發環境中,能夠禁止郵件發送是十分有用的。
如果設置項 `TESTING` 設置成 `True`,emails 將會被禁止發送。調用 `send()` 發送郵件實際上不會有任何郵件被發送。
另外在測試環境之中的話,你可以設置 `MAIL_SUPPRESS_SEND` 為 **True**,這也會有相同的效果。
然而,當單元測試的時候追蹤郵件是否發送成功也是十分有用的。
為了能夠追蹤發送郵件的“軌跡”,可以使用 `record_messages` 方法:
```
with mail.record_messages() as outbox:
mail.send_message(subject='testing',
body='test',
recipients=emails)
assert len(outbox) == 1
assert outbox[0].subject == "testing"
```
**outbox** 是一個 發送 `Message` 實例的列表。
為了使得上述代碼能夠正常運行,必須安裝 blinker 包。
需要注意的是以前的處理方式,即把 **outbox** 賦予給 `g` 對象已經過時。
## 頭注入
為了防止 [header injection](http://www.nyphp.org/PHundamentals/8_Preventing-Email-Header-Injection),嘗試著在郵件主題、發件人或者收件人中使用換行符將會拋出 `BadHeaderError` 異常。
## 信號量
New in version 0.4.
**Flask-Mail** 現在通過 `email_dispatched` 信號開始支持信號量。只要郵件被調度,信號就會發送(即使郵件沒有真正的發送,例如,在測試環境中)。
訂閱 `email_dispatched` 信號的函數使用 `Message` 實例作為第一參數,Flask app 實例作為一個可選的參數:
```
def log_message(message, app):
app.logger.debug(message.subject)
email_dispatched.connect(log_message)
```
## API
`class flask_mail.Mail(app=None)`
Manages email messaging
Parameters: **app** – Flask instance
`connect()`
Opens a connection to the mail host.
`send(message)`
Sends a single message instance. If TESTING is True the message will not actually be sent.
Parameters: **message** – a Message instance.
`send_message(*args, **kwargs)`
Shortcut for send(msg).
Takes same arguments as Message constructor.
Versionadded: 0.3.5
`class flask_mail.Attachment(filename=None, content_type=None, data=None, disposition=None, headers=None)`
Encapsulates file attachment information.
Versionadded:
0.3.5
Parameters:
* **filename** – filename of attachment
* **content_type** – file mimetype
* **data** – the raw file data
* **disposition** – content-disposition (if any)
`class flask_mail.Connection(mail)`
Handles connection to host.
`send(message, envelope_from=None)`
Verifies and sends message.
Parameters:
* **message** – Message instance.
* **envelope_from** – Email address to be used in MAIL FROM command.
`send_message(*args, **kwargs)`
Shortcut for send(msg).
Takes same arguments as Message constructor.
Versionadded: 0.3.5
`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)`
Encapsulates an email message.
Parameters:
* **subject** – email subject header
* **recipients** – list of email addresses
* **body** – plain text message
* **html** – HTML message
* **sender** – email sender address, or **MAIL_DEFAULT_SENDER** by default
* **cc** – CC list
* **bcc** – BCC list
* **attachments** – list of Attachment instances
* **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
`add_recipient(recipient)`
Adds another recipient to the message.
Parameters: **recipient** – email address of recipient.
`attach(filename=None, content_type=None, data=None, disposition=None, headers=None)`
Adds an attachment to the message.
Parameters:
* **filename** – filename of attachment
* **content_type** – file mimetype
* **data** – the raw file data
* **disposition** – content-disposition (if any)