由於博客要支持評論,因此咱們須要在文章有了新評論後發郵件通知管理員。並且,當管理員回覆了讀者的評論後,也須要發送郵件提醒讀者。html
爲了方便讀者使用示例程序,personalBlog中仍然使用Flask-Mail來發送郵件。讀者在運行程序前須要在項目根目錄內建立.env文件寫入對應的環境變量,以便讓發信功能正常工做。flask
由於郵件的內容很簡單,咱們將直接在發信函數中寫出正文內容,這裏只提供了HTML正文。咱們有兩個須要使用電子郵件的場景:app
一、當文章有新評論時,發送郵件給管理員;異步
二、當某個評論被回覆時,發送郵件給被回覆用戶。async
爲了方便使用,咱們在emails.py中分別爲這兩個使用場景建立了特定的發信函數,能夠直接在視圖函數中調用 。這些函數內部則經過咱們建立的通用發信函數send_email()來發送郵件,以下所示 :ide
personalBlog/emails.py: 提醒郵件函數函數
from flask import url_for def send_mail(subject, to, html): pass def send_new_comment_email(post): # blog.show_post是blog藍本下的show_post視圖函數 post_url = url_for('blog.show_post', post_id = post.id, _external = True) + '#comments' send_mail(subject = 'New comment', to = current_app.config['BLUEBLOG_ADMIN_EMAIL'], html = '<p>New comment in post <i>%s</i>, click the link below to check:</p>' '<p><a href="%s">%s</a></p>' '<p><small style = "color:#868e96">Do not reply this email.</small></p>' % (post.title, post_url, post_url)) def send_new_reply_email(comment): post_url = url_for('blog.show_post', post_id = comment.post_id, _external = True) + '#comments' send_mail(subject = 'New reply', to = comment.email, html = '<p>New reply for the comment you left in post <i>%s</i>, click the link below to check: </p>' '<p><a href="%s">%s</a></p>' '<p><small style="color: #868e96">Do not reply this email.</small></p>' % (comment.post.title, post_url, post_url))
send_new_comment_email()函數用來發送新評論提醒郵件。 咱們經過將url_for()函數的_external參數設爲True來構建外部連接。連接尾部的#comments是用來跳轉到頁面評論部分的URL片斷(URL fragment),comments是評論部分div元素的id值。這個函數接收表示文章的post對象做爲參數,從而生成文章正文的標題和連接。post
URL片斷又稱片斷標識符(fragment identifier),是URL中用來表示頁面中資源位置的短字符,以#開頭,對於HTML頁面來講,一個典型的示例是文章頁面的評論區。假設評論區的div元素id爲comment,若是咱們訪問http://example.com/post/7#comment,頁面加載完成後將會直接跳到評論部分。this
send_new_reply_email()函數則用來發送新回覆提醒郵件。這個發信函數接收comment對象做爲參數,用來構建郵件正文,所屬文章的主鍵值經過comment.post_id屬性獲取,標題則經過comment.post.titlle屬性獲取。url
在personalBlog源碼中,咱們沒有使用異步的方式發送郵件,若是你但願編寫一個異步發送郵件的通用發信函數send_mail(),和以前介紹的基本相同,以下所示
from threading import Thread from flask import current_app from flask_mail import Message from personalBlog.extensions import mail def _send_async_mail(app, message): with app.app_context(): mail.send(message) def send_async_mail(subjecct, to, html): app = current_app._get_current_object() # 獲取被代理的真實對象 message = Message(subjecct, recipients=[to], html = html) thr = Thread(target = _send_async_mail, args = [app, message]) thr.start() return thr
須要注意,由於咱們的程序是經過工廠函數建立的,因此實例化Thread類時,咱們使用代理對象current_app做爲args參數列表中app的值。另外,由於在新建線程時須要真正的程序對象來建立上下文,因此不能直接傳入current_app,而是傳入current_app調用_get_current_app()方法獲取的被代理的程序實例。