Flask專案:使用Flask-Mail + uwsgi的郵件傳送
自己寫了一個個人主頁,準備部署到阿里雲上,環境是
Flask + Nginx + MySQL + uwsgi + CentOS6.8
有一個(也是唯一一個^_^)需要後臺處理的業務就是郵件傳送,使用Flask-Mail來完成。
Flask-Mail 擴充套件提供了一個簡單的介面,可以在 Flask 應用中設定 SMTP, 使得可以在檢視以及指令碼中傳送郵件資訊。
開啟163郵箱的SMTP服務
我使用的是163郵箱的SMTP服務,首先需要先開啟該服務並獲得授權碼。在163郵箱的“設定-POP3/SMTP/IMAP”中可以開啟服務:
在“設定-客戶端授權密碼”中可以獲得授權碼,具體可能需要用到手機驗證:
安裝Flask-Mail
pip install Flask-Mail
配置Flask-Mail
配置項 預設值 功能
MAIL_SERVER localhost 郵箱伺服器
MAIL_PORT 25 埠
MAIL_USE_TLS False 是否使用TLS
MAIL_USE_SSL False 是否使用SSL
MAIL_DEBUG app.debug 是否為DEBUG模式,列印除錯訊息
MAIL_SUPPRESS_SEND app.testing 設定是否真的傳送郵件,True不傳送
MAIL_USERNAME None 使用者名稱,填郵箱
MAIL_PASSWORD None 密碼,填授權碼
MAIL_DEFAULT_SENDER None 預設傳送者,填郵箱
MAIL_MAX_EMAILS None 一次連線中的傳送郵件的上限
MAIL_ASCII_ATTACHMENTS False 如果 MAIL_ASCII_ATTACHMENTS 設定成 True 的話,檔名將會轉換成 ASCII 的。一般用於新增附件。
郵件是通過一個Mail例項進行管理的:
from flask import Flask
from flask_mail import Mail, Message
app = Flask(__name__)
...
app.config['MAIL_SERVER' ] = os.environ.get('MAIL_SERVER') or '你的郵箱伺服器'
app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME') or '你的郵箱'
app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD') or '你的郵箱授權碼'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USE_SSL'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:[email protected]/flask'
...
# 建立例項
mail = Mail(app)
傳送郵件
首先要建立傳送郵件的內容Message例項:
from flask-mail import Message
msg = Message(subject=subject, recipients=[to], sender=app.config['MAIL_USERNAME'])
其中,subject為主題,recipients為接收方,可以設定一個或多個收件人,也可以後續新增,sender為傳送方,如果設定了”MAIL_DEFAULT_SENDER”,就不必再填寫發件人,因為預設情況下會使用配置項的傳送人。
郵件內容可以包括主體以及/或者HTML:
msg.html = 'Email: ' + message[0] + '<br>Message: ' + message[1]
msg.body = 'Email: ' + message[0] + 'Message: ' + message[1]
最後,傳送郵件的時候請使用Flask應用設定的Mail例項:
mail.send(msg)
完整例子
from flask import Flask, render_template, request, flash, redirect, url_for, current_app
from flask_script import Manager
from flask_sqlalchemy import SQLAlchemy
from flask_mail import Mail, Message
from threading import Thread
import os
from flask_migrate import Migrate, MigrateCommand
from datetime import datetime
base_dir = os.path.abspath(os.path.dirname(__file__))
app = Flask(__name__)
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY') or 'idandan'
app.config['MAIL_SERVER'] = os.environ.get('MAIL_SERVER') or '你的郵箱伺服器'
app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME') or '你的郵箱'
app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD') or '你的郵箱授權碼'
app.config['MAIL_PORT'] = 465 # 設定郵箱埠為465,預設為25,由於阿里雲禁止了25埠,所以需要修改
app.config['MAIL_USE_SSL'] = True # 163郵箱需要開啟SSL
#database_uri = 'sqlite:///' + os.path.join(base_dir, 'data.sqlite')
#app.config['SQLALCHEMY_DATABASE_URI'] = database_uri
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:[email protected]/你的資料庫名'
# 建立例項
mail = Mail(app)
db = SQLAlchemy(app)
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)
# 資料庫模型類
class MessageModel(db.Model):
__tablename__ = 'message'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128))
email = db.Column(db.String(64))
message = db.Column(db.Text)
timestamp = db.Column(db.DateTime, default=datetime.utcnow())
# 傳送郵件
def send_mail(to, subject, message, **kwargs):
msg = Message(subject=subject, recipients=[to], sender=app.config['MAIL_USERNAME'])
msg.html = 'Email: ' + message[0] + '<br>Message: ' + message[1]
msg.body = 'Email: ' + message[0] + 'Message: ' + message[1]
mail.send(msg)
return 'ok'
# 檢視處理路由
@app.route('/send/', methods=['GET', 'POST'])
def send():
if request.method == 'POST':
# 接收form表單中傳遞過來的資料
name = request.form.get('name')
email = request.form.get('email')
message = request.form.get('message')
# 寫入資料庫
record = MessageModel(name=name, email=email, message=message)
db.session.add(record)
db.session.commit()
# 傳送郵件
send_mail('收件人郵箱', name, [email, message])
flash('Email send successfully')
return redirect(url_for('index'))
return render_template('index.html')
@app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
manager.run()
開始使用了非同步傳送,但是由於使用的是uwsgi,似乎由於GIL的原因,禁止了uwsgi的多執行緒(不確定是不是),所以導致郵件一直髮送不出去,測試了很久,將非同步傳送去掉了以後就成功了,同學們也可以測試一下。另外,在初始化MySQL時,報了”ModuleNotFoundError: No module named ‘MySQLdb’
“的錯誤,這個只要在配置”SQLALCHEMY_DATABASE_URI”的時候,加上一個”pymysql”就可以了,詳細可以見No module named ‘MySQLdb’
分割線
終於找到不能非同步傳送郵件的原因了,uwsgi預設時單執行緒的,每次都是結束後才能給伺服器傳送成功,在後臺啟動檔案”uwsgi.ini”中新增threads選項,指定執行緒數就可以了