做網(wǎng)站阿里云買哪個服務器好點汽車推廣軟文
??前言:本博客僅作記錄學習使用,部分圖片出自網(wǎng)絡,如有侵犯您的權(quán)益,請聯(lián)系刪除?
目錄
一、使用Flask-Mail發(fā)送電子郵件
1.1、配置Flask-Mail
1.2、構(gòu)建郵件數(shù)據(jù)
1.3、發(fā)送郵件
二、使用事務郵件服務SendGrid
2.1、注冊SendGrid
2.2、SendGrid SMTP轉(zhuǎn)發(fā)
2.3、SendGrid Web API轉(zhuǎn)發(fā)
三、電子郵件進階
3.1、提供HRML正文
3.2、使用Jinja2模板組織郵件正文
3.3、異步發(fā)送郵件
致謝
示例郵件:
郵件字段 | 字段值 |
---|---|
發(fā)信方(Sender) | Greygrey@helloflask.com |
收信方(To) | Zornzorn@example.com |
郵件主體(Subject) | Hello,World! |
郵件正文(Body) | Across the Great Wall we can reach every corner in the world. |
一、使用Flask-Mail發(fā)送電子郵件
擴展Flask-Mail包裝了Python標準庫中的smtplib包,簡化了在Flask程序中發(fā)送電子郵件的過程。
?pip install flask-mail
實例化Flask-Mail提供的Mail類并傳入程序?qū)嵗酝瓿沙跏蓟?#xff1a;
?from flask_mail import Mail?app = Flask(__name__)...mail = Mail(app)
1.1、配置Flask-Mail
Flask-Mail通過連接SMTP(Simple Mail Transfer Protocal,簡單郵件傳輸協(xié)議)服務器來發(fā)送郵件。在開發(fā)和測試階段,我們使用郵件服務提供商的SMTP服務器(比如Gmail),這時我們需要對Flask-Mail進行配置。
Flask-Mail常用配置變量:
配置鍵 | 說明 | 默認值 |
---|---|---|
MAIL_SERVER | 用于發(fā)送郵件的SMTP服務器 | localhost |
MAIL_PORT | 發(fā)送端口 | 25 |
MAIL_USE_TLS | 是否使用STRTTLS | False |
MAIL_USE_SSL | 是否使用SSL/TLS | False |
MAIL_USERNAME | 發(fā)送服務器的用戶名 | None |
MAIL_PASSWORD | 發(fā)送服務器的密碼 | None |
MAIL_DEFAULT_SENDER | 默認的發(fā)信人 | None |
對發(fā)送的郵件進行加密可以避免在發(fā)送過程中被第三方截獲和篡改。SSL(Security Socket Layer,安全套接字層)和TLS(Transport Layer Security,傳輸層安全)是兩種常用的電子郵件安全協(xié)議。TLS繼承了SSL,并在SSL的基礎上做了一些改進。通過將MAIL_USE_SSL設置為True開啟。STARTTLS是另一種加密方式,它會對不安全的連接進行升級。
?# 1、SSL/TLS加密:MAIL_USE_SLL = TrueMAIL_PORT = 465?# 2、STARTTLS加密:MAIL_USE_TLS = TrueMAIL_PORT = 587
(當不對郵件進行加密時,郵件服務器的端口使用默認的25端口)
常見的電子郵箱服務提供商的STMP配置信息:
電子郵件服務提供商 | MAIL_SERVER | MAIL_USERNAME | MAIL_PASSWORD | 額外步驟 |
---|---|---|---|---|
Gmail | smtp.gmail.com | 郵箱地址 | 郵箱密碼 | 開啟"Allow less secure apps",在本地設置VPN代理 |
QQ郵箱 | smtp.qq.com | 郵箱地址 | 授權(quán)碼 | 開啟SMTP服務并獲取授權(quán)碼 |
新浪郵件 | smtp.sina.com | 郵箱地址 | 郵箱密碼 | 開啟SMTP服務 |
163郵箱 | smtp.163.com | 郵箱地址 | 授權(quán)碼 | 開啟SMTP服務并設置授權(quán)碼 |
Outlook/Hotmail | smtp.live.com或smtp.office365.com | 郵箱地址 | 郵箱密碼 | 無 |
(163郵箱的SMTP服務不支持STARTTLS,需要使用SSL/TLS加密。就是將MAIL_USE_SSL設為True,MAIL_PORT設為465)
Gmail、Outlook、QQ郵箱等這類服務被稱為EPA(Email Service Procider),只適用于個人業(yè)務使用,不適合用來發(fā)送事務郵件。對于需要發(fā)送大量郵件的事務性郵件任務,更好的選擇是使用自己配置的SMTP服務器或是使用類似SendGrid、Mailgun的事務郵件服務提供商。
在程序中,隨著配置的逐漸增多,我們改用app.config對象的update()方法來加載配置:
?import osfrom flask import Flaskfrom flask_mail import Mail?app = Flask(__name__)?app.config.update(MAIL_SERVER=os.getenv('MAIL_SERVER'),MAIL_PORT=587,MAIL_USE_TLS=True,MAIL_USERNAME=os.getenv('MAIL_USERNAME'),MAIL_PASSWORD=os.getenv('MAIL_PASSWORD'),MAIL_DEFAULT_SENDER=('Grey Li', os.getenv('MAIL_USERNAME')))mail = Mail(app)
在我們的配置中,郵箱賬戶和密碼屬于敏感信息,不能直接寫在腳本中,所以設置為從系統(tǒng)環(huán)境變量中獲取。
1.2、構(gòu)建郵件數(shù)據(jù)
下面借助Python Shell演示。郵件通過從Flask-Mail中導入的Message類表示,而發(fā)信功能通過我們在程序包的構(gòu)建文件中創(chuàng)建的mail對象實現(xiàn):
?$ flask shell>>> from flask_mail import Message>>> from app import mail
一封郵件至少包含主題、收件人、正文、發(fā)信人這幾個。發(fā)信人在前用MAIL_DEFUALT_SENDER配置變量指定過了,剩下的分別通過Message類的構(gòu)造方法中的subject、recipients、body關鍵字傳入?yún)?shù),其中recipients是包含一電子郵件地址的列表。
?>>> message = Message(subject='Hello,World!',recipients=['Zorn <zorn@example.com>'],body='Across the Great Wall we can reach every corner in the world.')
(和發(fā)信人類似,收信人字符串有兩種新式:'Zorn zorn@example.com'或'zorn@example.com')
1.3、發(fā)送郵件
通過對mail對象調(diào)用send()方法,傳入我們在上面構(gòu)建的郵件對象即可發(fā)送郵件:
?>>> mail.send(message)
完整的發(fā)送示例代碼:
?from flask import Flaskfrom flask_mail import Mail,Message...message = Message(subject='Hello,World!',recipients=['Zorn <zorn@example.com>'],body='Across the Great Wall we can reach every corner in the world.')mail.send(message)
為了方便重用,我們把這些代碼包裝成一個通用的發(fā)信函數(shù)send_mail():
...
def send_mail(subject,to,body):message = Message(subject,recipients=[to],body=body)mail.send(message)
假設我們程序是一個周刊訂閱程序,當用戶在表單中填寫了正確的Email地址時,我們就發(fā)送一封郵件來通知用戶訂閱成功。通過在index視圖中調(diào)用send_mail()即可發(fā)送郵件:
@app.route('/subscript',methods=['GET','POST'])
def subscript():form = SubscribeForm()if form.validate_on_submit():email = form.email.dataflash('Welcome on board!')send_mail('Subscribe Success!',email,'Hello,thank you for subscribing Flask Weekly!')return redirect(url_for('index'))return render_template('index.html',form=form)
二、使用事務郵件服務SendGrid
在生產(chǎn)環(huán)境中,除了自己安裝運行郵件服務器外,更方便的做法是使用事務郵件服務,比如Mailgun、Sendgrid等。這兩個郵件服務對免費賬戶分別提供每月1萬封和3000封的免費額度,完全足夠在測試使用或在小型程序中使用。Mailgun在注冊免費賬戶時需要填寫信用卡,而Sendgrid沒有這一限制。
2.1、注冊SendGrid
登錄官網(wǎng)注冊一個免費賬戶,訪問https://app.sendgrid.com/signup,填寫信息等完成注冊。注冊完成后,需要為當前的項目創(chuàng)建一個API密鑰,用于在程序中發(fā)送郵件時進行認證。
創(chuàng)建成功后復制密鑰,然后保存到.env文件中,待會使用它來作為發(fā)信賬戶的密碼:
SENDRID_API_KEY=your_key_here
(API密鑰被創(chuàng)建一次后僅顯示一次,一旦關閉了顯示界面,將無法再次查看。)
2.2、SendGrid SMTP轉(zhuǎn)發(fā)
創(chuàng)建好API密鑰后,就可以通過SendGrid提供的SMTP服務器發(fā)送電子郵件了。
MAIL_SERVER = 'smtp.sendgrid.net'
MAIL_PORT = 587
MAIL_USE_TLS = True
MAIL_USERNAME = 'apikey'
MAIL_PASSWORD = os.getenv('SENDGRID_API_KEY') # 從環(huán)境變量中讀取API密鑰
2.3、SendGrid Web API轉(zhuǎn)發(fā)
在程序中向SendGrid提供的Web API發(fā)出一個POST請求,并附帶必要的信息,比如密鑰、郵件主題、收件人、正文等。示例:
POST https://api.sendgrid.com/v3/mail/send
'Authorization: Bearer YOUR_API_KEY'
'Content-Type: application/json''{"personalizations":[{"to":[{"email":"zorn@example.com"}]}],"from":{"email":"noreply@helloflask.com"},"subject":"Hello,World!","content":[{"type":"text/plain","value":"Across the Great Wall we can reach every corner in the World."}]}'
在命令行中使用curl一類的工具,或是使用任意一個用于請求的Python庫即可發(fā)送電子郵件,比如requests。為了更方便在Python中構(gòu)建郵件內(nèi)容和發(fā)送郵件,我們可以使用SendGrid提供的官方Python SDK---SendGrid-Python:
pip install sendgrid
2.3.1、創(chuàng)建發(fā)信對象
首先需要實例化SendGridAPIClient類創(chuàng)建一個發(fā)信客戶端對象:
>>> from sendgrid import SendGridAPIClient
>>> sg = SendGridAPIClient(api_key=os.getenv('SENDGRID_API_KEY'))
2.3.2、構(gòu)建郵件數(shù)據(jù)
from sendgrid.helpers.mail import Email,Content,Mail
from_email = Email('norn@helloflask.com')
to_email = Email('zorn@example.com')
subject = 'Hello World!'
content = Content('text/plain','Across the Great Wall we can reach every corner in the World.')
mail = Mail(from_email,subject,to_email,content)
2.3.3、發(fā)送郵件
通過對表示郵件對象的sg對象調(diào)用sg.client.mail.send.post()方法,并將表示數(shù)據(jù)的字典使用關鍵字request_body傳入即可發(fā)送發(fā)信的POST請求:
sg.client.mail.send.post(request_body=mail.get())
發(fā)信的方法會返回響應,我們可以查看響應的內(nèi)容:
response = sg.client.mail.send.post(request_body=mail.get())
print(response.status_code)
print(response.body)
print(response.headers)
同樣的,可以創(chuàng)建一個發(fā)信函數(shù)用來在視圖函數(shù)中調(diào)用:
import sendgrid
import os
from sendgrid.helpers.mail import *def send_email(subject,to,body):sg = SendGridAPIClient(api_key=os.getenv('SENDGRID_API_KEY'))from_email = Email('norn@helloflask.com')to_email = Email(to)content = Content('text/plain',body)mail = Mail(from_email,subject,to_email,content)response = sg.client.mail.send.post(request_body=mail.get())
三、電子郵件進階
3.1、提供HRML正文
一封電子郵件的正文可以是純文本(text/plain),也可以是HTML格式的文本(text/html)。出于更安全的考慮,一封電子郵件應該既包含純文本又包含HTML格式的正文。HTML格式正文將被優(yōu)先讀取;對于HTML郵件正文的編寫:
- 使用Tabel布局,而不是Div布局
- 使用行內(nèi)(inline)樣式定義,比如:
<span style="font-family:Arial,Helvetica,sans-serif;font-size:12px;color:##000000;">Hello Email!</span>
- 使用比較基礎的CSS屬性,避免使用快捷屬性(比如background)和定位屬性(比如float、position)
- 郵件正文的寬度不超過600px
- 避免使用JavaScript代碼
- 避免使用背景圖片
在Flask-Mail中,我們使用Message類實例來構(gòu)建郵件。和純文本正文類似,HTML正文可以在實例化時傳入html參數(shù)指定:
message = Message(...,body='純文本正文',html='<h1>HTML正文</h1>')
或是通過類屬性message.html指定:
message = Message(...)
message.body = '純正文文本'
message.html = '<h1>HTML文本</h1>'
在SendGrid-Python中,使用Content類構(gòu)建郵件正文時傳入的第一個type_ 參數(shù)指定了郵件正文的MIME類型。若想同時提供兩種格式的正文,那么就在使用Mail類構(gòu)建郵件數(shù)據(jù)時傳入一個包含兩個Content類實例的列表作為正文content的參數(shù)值:
from sendgrid.helpers.mail import *
...
text_content = Content("text/plain","純正文文本")
html_content = Content("text/html","<h1>HTML文本</h1>")
mail = Mail(from_email,subject,to_email,content=[text=content,html_content])
3.2、使用Jinja2模板組織郵件正文
大多數(shù)情況下,我們需要動態(tài)構(gòu)建郵件正文。示例一個純文本郵件模板subscribe.txt:
Hello {{ name }},
Thank you for subscribing Flask weekly!
Enjoy the reading :)Visit this link to unsubscribe: {{ url_for('unsubscribe',_external=True) }}
為了同時支持純文本和HTML格式的郵件正文,每一類郵件我們都需要分別創(chuàng)建HTML和純文本格式的模板。
<div style="width: 580px; padding: 20px;"><h3>Hello {{ name }}</h3><p>Thank you for subscribing Flask Weekly!</p><p>Enjoy the reading :)</p><smail style="color: #868e96;">Click here to <a href="{{ url_for('unsubscribe',_external=True) }}">unsubscribe</a>.</smail>
</div>
以上面創(chuàng)建的發(fā)信函數(shù)為例,在發(fā)送郵件的視圖函數(shù)中使用render_template()函數(shù)渲染郵件正文,并傳入相應的變量:
from flask import render_template
from flask_mail import Messagedef send_subscribe_mail(subject,to,**kwargs):message = Message(subject,recipients=[to],sender='Flask Weekly <%s>' %os.getenv('MAIL_USERNAME'))message.body = render_template('emails/subscribe.txt',**kwargs)message.html = render_template('emails/subscribe.html',**kwargs)mail.send(message)
3.3、異步發(fā)送郵件
為了避免延遲,我們可以將發(fā)信函數(shù)放入后臺線程異步執(zhí)行,以Flask-Mail為例:
from threading import Threaddef _send_async_mail(app,message):with app.app_context():mail.send(message)def send_mail(subject,to,body):message = Message(subject,recipients=[to],body=body)thr = Thread(target=_send_async_mail,args=[app,message])thr.start()return thr
因為Flask_Mail的send()方法內(nèi)部的調(diào)用邏輯中使用了current_app變量,而這個變量只在激活的程序上下文中才存在,這里在后臺線程調(diào)用發(fā)信函數(shù),但是后臺線程并沒有程序上下文存在。為了正常實現(xiàn)發(fā)信功能,我們傳入程序?qū)嵗齛pp作為參數(shù),并調(diào)用app,app_context()手動激活程序上下文。
致謝
在此,我要對所有為知識共享做出貢獻的個人和機構(gòu)表示最深切的感謝。同時也感謝每一位花時間閱讀這篇文章的讀者,如果文章中有任何錯誤,歡迎留言指正。?
學習永無止境,讓我們共同進步!!