自己写了一个个人主页,准备部署到阿里云上,环境是
Flask + Nginx + MySQL + uwsgi + CentOS6.8
有一个(也是唯一一个^_^)需要后台处理的业务就是邮件发送,使用Flask-Mail来完成。
Flask-Mail 扩展提供了一个简单的接口,可以在 Flask 应用中设置 SMTP, 使得可以在视图以及脚本中发送邮件信息。
我使用的是163邮箱的SMTP服务,首先需要先开启该服务并获得授权码。在163邮箱的“设置-POP3/SMTP/IMAP”中可以开启服务:
在“设置-客户端授权密码”中可以获得授权码,具体可能需要用到手机验证:
pip install 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:dzd123@localhost/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] + '
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:dzd123@localhost/你的数据库名'
# 创建实例
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] + '
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选项,指定线程数就可以了