在大多數教程中,我們將不遺余力地介紹如何使用數據庫。今天,讓我們暫時忘記數據庫,而是關註web應用程序中的另壹個重要功能:如何向用戶推送電子郵件。
在輕量級應用程序中,我們可能會添加以下電子郵件服務功能:當用戶有新粉絲時,我們會發送電子郵件通知用戶。有許多方法可以實現這壹特性,我們希望提供壹個可重用的通用框架來處理它。
燒瓶郵件遊戲攻略
對我們來說幸運的是,已經有許多外部插件來處理電子郵件。雖然我們不能100%按照我們的想法去做,但已經相當接近了。
在虛擬環境中安裝Flask-Mail非常簡單。Windows以外的用戶可以使用以下命令來安裝:
1
燒瓶/垃圾箱/pip安裝燒瓶-郵件
Windows用戶的安裝略有不同,因為Flask-Mail使用的壹些模塊無法在Windows系統上運行。您可以使用以下命令:
1
flaskScriptspip install-no-deps lamson chardet flask-mail
配置:
回想壹下上壹篇文章中的單元測試案例,我們通過添加配置來支持這樣壹個功能:當應用程序的某個版本測試錯誤時,我們可以通過電子郵件通知我們。從這個例子中,我們可以看到如何配置郵件支持。
再次提醒大家,我們需要設置兩個方面:
郵件服務器信息
用戶電子郵件地址
以下是上壹篇文章中使用的配置。
#電子郵件服務器
郵件服務器=
MAIL_PORT = 25
MAIL_USE_TLS = False
MAIL_USE_SSL = False
郵件用戶名=您
郵件密碼=您的密碼
#管理員列表
管理員= [you@example.com】
沒有實用的郵件服務器和郵箱。現在讓我們舉個例子來看看如何使用gmail電子郵件帳戶發送郵件:
#電子郵件服務器
郵件服務器=
MAIL_PORT = 465
MAIL_USE_TLS = False
MAIL_USE_SSL = True
MAIL_USERNAME =您的gmail用戶名
MAIL_PASSWORD =您的gmail密碼
#管理員列表
管理員= [your-gmail-username@gmail.com】
此外,我們還可以初始化壹個郵件對象來連接SMTP郵件服務器並發送郵件:
1
2
從flask.ext.mail導入郵件
郵件=郵件(應用程序)
嘗試發送電子郵件!
為了理解flask-mail的工作原理,我們可以從命令行發送壹封電子郵件來查看。進入python shell並執行以下腳本:
七
從flask.ext.mail導入郵件
從應用程序導入郵件
從配置導入管理員
msg =消息(測試主題,發件人=管理員【0】,收件人=管理員)
msg.body =正文
msg.html = b html/b主體
郵件發送(消息)
上述代碼將根據inconfig.py中配置的電子郵件地址列表向所有郵箱發送壹封電子郵件,其中第壹個郵箱為發件人。電子郵件內容將以文本和html格式顯示,您可以看到的格式取決於您的電子郵件客戶端。
多麽簡單和緊湊!您現在可以將它集成到您的應用程序中。
郵件框架
我們現在可以編寫壹個幫助函數來發送電子郵件。這是上述測試的壹般版本。我們將此函數放入壹個新的原始文件中用於郵件支持(fileapp/emails.py):
七
八
從flask.ext.mail導入郵件
從應用程序導入郵件
def send_email(主題、發件人、收件人、文本正文、html正文):
msg =消息(主題、發件人、收件人)
msg.body = text_body
msg.html = html _ body
郵件發送(消息)
Flask-Mail的郵件支持超出了我們當前的使用範圍,並且密件抄送和附件等功能將不會在此應用程序中使用。
關註者提醒
現在我們已經有了發送電子郵件的基本框架,我們可以編寫壹個函數來發送關註者提醒(fileapp/emails.py):
11
從燒瓶導入渲染模板
從配置導入管理員
def follower_notification(已跟蹤,follower):
send_email(【微博】%s正在關註您!% follower.nickname,
管理員【0】,
【已關註。電子郵件】,
render _ template(follower _ email . txt,
用戶=被關註,關註者=關註者),
render _ template(follower _ email . html,
用戶=被關註,關註者=關註者))
妳發現這裏有什麽驚喜嗎?我們的老朋友render_template函數曾經出現過。
如果您還記得的話,我們使用這個函數在視圖中呈現模板。就像在視圖中編寫html不好壹樣,使用電子郵件模板是壹個理想的選擇。我們應該盡可能地將邏輯和表示分開,這樣電子郵件模板將與其他模板壹起放在模板文件夾中。
因此,我們需要為關註者提醒電子郵件編寫壹份純文本和網頁版的電子郵件模板。以下是純文本版本(file app/templates/follower _ email . txt):
七
八
九
尊敬的{{user.nickname}},
{{follower.nickname}}現在是關註者。單擊以下鏈接訪問{ { follower.nickname } }的個人資料頁面:
{{url_for(用戶,昵稱= follower .昵稱,_ external = True)} }
問候,
微博管理員
以下郵件為網頁版,效果會更好(file app/templates/follower _ email . html):
11
12
13
pDear { { user.nickname } },/p
pa href = { { URL _ for(user,nickname = follower.nickname,_ external = True)} } { { follower . nickname } }/a現在是追隨者。/p
桌子
tr valign=top
TD img src = { { follower . avatar(50)} }/TD
(美)財政部(Treasury Department)
a href = { { URL _ for(user,nickname = follower.nickname,_ external = True)} } { { follower . nickname } }/ABR/
{{follower.about_me}}
/td
/tr
/表格
預告片,/p
p代碼微博/代碼管理/p
註意:模板中url_for函數的_external = True參數的含義。默認情況下,url_for函數生成的url是相對於我們的域名的。比如URL _ for(index)函數的返回值是/index,但email是我們想要的。
最後壹步是處理“follow”過程,即觸發電子郵件提醒時的查看功能。(fileapp/views.py):
七
八
九
從電子郵件導入關註者_通知
@ app . route(/follow/昵稱)
@登錄_必填
定義跟隨(昵稱):
user = User.query.filter_by(昵稱=昵稱)。首先()
# ...
關註者通知(用戶,普通用戶)
返回重定向(url_for(用戶,昵稱=昵稱))
現在,您可以創建兩個用戶(如果還沒有用戶)並嘗試讓壹個用戶跟隨另壹個用戶以了解電子郵件提醒是如何工作的。
就這樣嗎?我們結束了嗎?
我們可能會非常興奮地完成這項工作,並從未完成的列表中刪除電子郵件提醒功能。
但是,如果您現在測試該應用程序,您會發現當您單擊follow鏈接時,頁面將需要2到3秒鐘的響應時間,並且瀏覽器將刷新,這在以前是不可用的。
發生了什麽事?
問題是Flask-Mail使用同步模式發送電子郵件。從發送電子郵件到發送電子郵件並將其發送回瀏覽器的這段時間內,Web服務器將壹直處於阻塞狀態。如果我們試圖向服務器發送電子郵件,它會很慢,甚至更糟的是,會暫時脫機。妳能想象會發生什麽嗎?非常糟糕。
這是壹個可怕的限制。發送電子郵件應該是後臺任務,不會幹擾網絡服務器。讓我們看看如何解決這個問題。
在Python中執行異步調用
我們希望send_email函數在發送電子郵件後立即返回,我們需要將電子郵件移動到後臺進程中進行異步執行。
事實上,python已經提供了對異步任務的支持,但實際上,還有其他方法可以實現異步任務,例如線程和多進程模塊。
每當我們需要發送電子郵件時,啟動壹個線程來處理它比啟動壹個全新的進程節省資源。因此,讓我們將mail . send(msg)調用放在另壹個線程中。(fileapp/emails.py):
11
從線程導入線程
定義發送異步電子郵件(消息):
郵件發送(消息)
def send_email(主題、發件人、收件人、文本正文、html正文):
msg =消息(主題,發件人=發件人,收件人=收件人)
msg.body = text_body
msg.html = html _ body
thr =線程。線程(target = send_async_email,args =【msg】)
thr.start()
如果您測試“關註”功能,現在您會發現在發送電子郵件之前瀏覽器會刷新。
所以,我們已經實現了異步傳輸,但是如果我們將來在其他地方需要異步功能,我們是否需要再次實現它?
過程是壹樣的,所以每種情況下都會有重復的代碼,這是非常糟糕的。
我們可以通過裝飾器來改進代碼。使用裝飾器的代碼如下:
11
從裝飾者異步導入
@異步
定義發送異步電子郵件(消息):
郵件發送(消息)
def send_email(主題、發件人、收件人、文本正文、html正文):
msg =消息(主題,發件人=發件人,收件人=收件人)
msg.body = text_body
msg.html = html _ body
發送異步電子郵件
好些了,對嗎?
實現該方法的代碼實際上非常簡單,創建壹個新的源文件(fileapp/decorators.py):
七
從線程導入線程
def異步(f):
def包裝器(*args、**kwargs):
thr = Thread(target = f,args = args,kwargs = kwargs)
thr.start()
返回包裝
現在我們已經為異步任務創建了壹個有用的框架,可以說我們已經完成了它!
作為壹個練習,讓我們思考壹下為什麽這個方法似乎使用進程而不是線程。我們不希望每次需要發送電子郵件時都啟動壹個進程,因此我們可以使用Poolclass而不是multiprocessingmodule。該類將創建指定數量的進程(這些都是主進程的子進程),這些子進程將通過apply_asyncmethod發送到進程池,等待接受任務才能工作。對於壹個繁忙的網站來說,這可能是壹種有趣的方式,但我們仍將保持當前的線程模式。