做網(wǎng)站阿里云買哪個(gè)服務(wù)器好點(diǎn)汽車推廣軟文
??前言:本博客僅作記錄學(xué)習(xí)使用,部分圖片出自網(wǎng)絡(luò),如有侵犯您的權(quán)益,請(qǐng)聯(lián)系刪除?
目錄
一、使用Flask-Mail發(fā)送電子郵件
1.1、配置Flask-Mail
1.2、構(gòu)建郵件數(shù)據(jù)
1.3、發(fā)送郵件
二、使用事務(wù)郵件服務(wù)SendGrid
2.1、注冊(cè)SendGrid
2.2、SendGrid SMTP轉(zhuǎn)發(fā)
2.3、SendGrid Web API轉(zhuǎn)發(fā)
三、電子郵件進(jìn)階
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ā)送電子郵件
擴(kuò)展Flask-Mail包裝了Python標(biāo)準(zhǔn)庫中的smtplib包,簡化了在Flask程序中發(fā)送電子郵件的過程。
?pip install flask-mail
實(shí)例化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é)議)服務(wù)器來發(fā)送郵件。在開發(fā)和測(cè)試階段,我們使用郵件服務(wù)提供商的SMTP服務(wù)器(比如Gmail),這時(shí)我們需要對(duì)Flask-Mail進(jìn)行配置。
Flask-Mail常用配置變量:
配置鍵 | 說明 | 默認(rèn)值 |
---|---|---|
MAIL_SERVER | 用于發(fā)送郵件的SMTP服務(wù)器 | localhost |
MAIL_PORT | 發(fā)送端口 | 25 |
MAIL_USE_TLS | 是否使用STRTTLS | False |
MAIL_USE_SSL | 是否使用SSL/TLS | False |
MAIL_USERNAME | 發(fā)送服務(wù)器的用戶名 | None |
MAIL_PASSWORD | 發(fā)送服務(wù)器的密碼 | None |
MAIL_DEFAULT_SENDER | 默認(rèn)的發(fā)信人 | None |
對(duì)發(fā)送的郵件進(jìn)行加密可以避免在發(fā)送過程中被第三方截獲和篡改。SSL(Security Socket Layer,安全套接字層)和TLS(Transport Layer Security,傳輸層安全)是兩種常用的電子郵件安全協(xié)議。TLS繼承了SSL,并在SSL的基礎(chǔ)上做了一些改進(jìn)。通過將MAIL_USE_SSL設(shè)置為True開啟。STARTTLS是另一種加密方式,它會(huì)對(duì)不安全的連接進(jìn)行升級(jí)。
?# 1、SSL/TLS加密:MAIL_USE_SLL = TrueMAIL_PORT = 465?# 2、STARTTLS加密:MAIL_USE_TLS = TrueMAIL_PORT = 587
(當(dāng)不對(duì)郵件進(jìn)行加密時(shí),郵件服務(wù)器的端口使用默認(rèn)的25端口)
常見的電子郵箱服務(wù)提供商的STMP配置信息:
電子郵件服務(wù)提供商 | MAIL_SERVER | MAIL_USERNAME | MAIL_PASSWORD | 額外步驟 |
---|---|---|---|---|
Gmail | smtp.gmail.com | 郵箱地址 | 郵箱密碼 | 開啟"Allow less secure apps",在本地設(shè)置VPN代理 |
QQ郵箱 | smtp.qq.com | 郵箱地址 | 授權(quán)碼 | 開啟SMTP服務(wù)并獲取授權(quán)碼 |
新浪郵件 | smtp.sina.com | 郵箱地址 | 郵箱密碼 | 開啟SMTP服務(wù) |
163郵箱 | smtp.163.com | 郵箱地址 | 授權(quán)碼 | 開啟SMTP服務(wù)并設(shè)置授權(quán)碼 |
Outlook/Hotmail | smtp.live.com或smtp.office365.com | 郵箱地址 | 郵箱密碼 | 無 |
(163郵箱的SMTP服務(wù)不支持STARTTLS,需要使用SSL/TLS加密。就是將MAIL_USE_SSL設(shè)為True,MAIL_PORT設(shè)為465)
Gmail、Outlook、QQ郵箱等這類服務(wù)被稱為EPA(Email Service Procider),只適用于個(gè)人業(yè)務(wù)使用,不適合用來發(fā)送事務(wù)郵件。對(duì)于需要發(fā)送大量郵件的事務(wù)性郵件任務(wù),更好的選擇是使用自己配置的SMTP服務(wù)器或是使用類似SendGrid、Mailgun的事務(wù)郵件服務(wù)提供商。
在程序中,隨著配置的逐漸增多,我們改用app.config對(duì)象的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)
在我們的配置中,郵箱賬戶和密碼屬于敏感信息,不能直接寫在腳本中,所以設(shè)置為從系統(tǒng)環(huán)境變量中獲取。
1.2、構(gòu)建郵件數(shù)據(jù)
下面借助Python Shell演示。郵件通過從Flask-Mail中導(dǎo)入的Message類表示,而發(fā)信功能通過我們?cè)诔绦虬臉?gòu)建文件中創(chuàng)建的mail對(duì)象實(shí)現(xiàn):
?$ flask shell>>> from flask_mail import Message>>> from app import mail
一封郵件至少包含主題、收件人、正文、發(fā)信人這幾個(gè)。發(fā)信人在前用MAIL_DEFUALT_SENDER配置變量指定過了,剩下的分別通過Message類的構(gòu)造方法中的subject、recipients、body關(guān)鍵字傳入?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ā)送郵件
通過對(duì)mail對(duì)象調(diào)用send()方法,傳入我們?cè)谏厦鏄?gòu)建的郵件對(duì)象即可發(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)
為了方便重用,我們把這些代碼包裝成一個(gè)通用的發(fā)信函數(shù)send_mail():
...
def send_mail(subject,to,body):message = Message(subject,recipients=[to],body=body)mail.send(message)
假設(shè)我們程序是一個(gè)周刊訂閱程序,當(dāng)用戶在表單中填寫了正確的Email地址時(shí),我們就發(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)
二、使用事務(wù)郵件服務(wù)SendGrid
在生產(chǎn)環(huán)境中,除了自己安裝運(yùn)行郵件服務(wù)器外,更方便的做法是使用事務(wù)郵件服務(wù),比如Mailgun、Sendgrid等。這兩個(gè)郵件服務(wù)對(duì)免費(fèi)賬戶分別提供每月1萬封和3000封的免費(fèi)額度,完全足夠在測(cè)試使用或在小型程序中使用。Mailgun在注冊(cè)免費(fèi)賬戶時(shí)需要填寫信用卡,而Sendgrid沒有這一限制。
2.1、注冊(cè)SendGrid
登錄官網(wǎng)注冊(cè)一個(gè)免費(fèi)賬戶,訪問https://app.sendgrid.com/signup,填寫信息等完成注冊(cè)。注冊(cè)完成后,需要為當(dāng)前的項(xiàng)目創(chuàng)建一個(gè)API密鑰,用于在程序中發(fā)送郵件時(shí)進(jìn)行認(rèn)證。
創(chuàng)建成功后復(fù)制密鑰,然后保存到.env文件中,待會(huì)使用它來作為發(fā)信賬戶的密碼:
SENDRID_API_KEY=your_key_here
(API密鑰被創(chuàng)建一次后僅顯示一次,一旦關(guān)閉了顯示界面,將無法再次查看。)
2.2、SendGrid SMTP轉(zhuǎn)發(fā)
創(chuàng)建好API密鑰后,就可以通過SendGrid提供的SMTP服務(wù)器發(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ā)出一個(gè)POST請(qǐng)求,并附帶必要的信息,比如密鑰、郵件主題、收件人、正文等。示例:
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一類的工具,或是使用任意一個(gè)用于請(qǐng)求的Python庫即可發(fā)送電子郵件,比如requests。為了更方便在Python中構(gòu)建郵件內(nèi)容和發(fā)送郵件,我們可以使用SendGrid提供的官方Python SDK---SendGrid-Python:
pip install sendgrid
2.3.1、創(chuàng)建發(fā)信對(duì)象
首先需要實(shí)例化SendGridAPIClient類創(chuàng)建一個(gè)發(fā)信客戶端對(duì)象:
>>> 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ā)送郵件
通過對(duì)表示郵件對(duì)象的sg對(duì)象調(diào)用sg.client.mail.send.post()方法,并將表示數(shù)據(jù)的字典使用關(guān)鍵字request_body傳入即可發(fā)送發(fā)信的POST請(qǐng)求:
sg.client.mail.send.post(request_body=mail.get())
發(fā)信的方法會(huì)返回響應(yīng),我們可以查看響應(yīng)的內(nèi)容:
response = sg.client.mail.send.post(request_body=mail.get())
print(response.status_code)
print(response.body)
print(response.headers)
同樣的,可以創(chuàng)建一個(gè)發(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())
三、電子郵件進(jìn)階
3.1、提供HRML正文
一封電子郵件的正文可以是純文本(text/plain),也可以是HTML格式的文本(text/html)。出于更安全的考慮,一封電子郵件應(yīng)該既包含純文本又包含HTML格式的正文。HTML格式正文將被優(yōu)先讀取;對(duì)于HTML郵件正文的編寫:
- 使用Tabel布局,而不是Div布局
- 使用行內(nèi)(inline)樣式定義,比如:
<span style="font-family:Arial,Helvetica,sans-serif;font-size:12px;color:##000000;">Hello Email!</span>
- 使用比較基礎(chǔ)的CSS屬性,避免使用快捷屬性(比如background)和定位屬性(比如float、position)
- 郵件正文的寬度不超過600px
- 避免使用JavaScript代碼
- 避免使用背景圖片
在Flask-Mail中,我們使用Message類實(shí)例來構(gòu)建郵件。和純文本正文類似,HTML正文可以在實(shí)例化時(shí)傳入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)建郵件正文時(shí)傳入的第一個(gè)type_ 參數(shù)指定了郵件正文的MIME類型。若想同時(shí)提供兩種格式的正文,那么就在使用Mail類構(gòu)建郵件數(shù)據(jù)時(shí)傳入一個(gè)包含兩個(gè)Content類實(shí)例的列表作為正文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ù)情況下,我們需要?jiǎng)討B(tài)構(gòu)建郵件正文。示例一個(gè)純文本郵件模板subscribe.txt:
Hello {{ name }},
Thank you for subscribing Flask weekly!
Enjoy the reading :)Visit this link to unsubscribe: {{ url_for('unsubscribe',_external=True) }}
為了同時(shí)支持純文本和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ù)渲染郵件正文,并傳入相應(yīng)的變量:
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ù)放入后臺(tái)線程異步執(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
因?yàn)镕lask_Mail的send()方法內(nèi)部的調(diào)用邏輯中使用了current_app變量,而這個(gè)變量只在激活的程序上下文中才存在,這里在后臺(tái)線程調(diào)用發(fā)信函數(shù),但是后臺(tái)線程并沒有程序上下文存在。為了正常實(shí)現(xiàn)發(fā)信功能,我們傳入程序?qū)嵗齛pp作為參數(shù),并調(diào)用app,app_context()手動(dòng)激活程序上下文。
致謝
在此,我要對(duì)所有為知識(shí)共享做出貢獻(xiàn)的個(gè)人和機(jī)構(gòu)表示最深切的感謝。同時(shí)也感謝每一位花時(shí)間閱讀這篇文章的讀者,如果文章中有任何錯(cuò)誤,歡迎留言指正。?
學(xué)習(xí)永無止境,讓我們共同進(jìn)步!!