Python Flask学习_使用Flask-Mail集成到WebApp中

python标准库中内置了邮件支持模块smtplib,但是包装了smtplib的Flask-Mail能更好的和Flask程序集成。

Flask-Mail连接到SMTP(简单邮件传输协议:simple mail transfer protocol)服务器,把邮件交给这个服务器发送。

一、安装和相关配置参数

# pyCharm Terminal

pip install flask-mail


什么是Shell:

shell

 

(计算机壳层)

在计算机科学中,Shell俗称壳(用来区别于核),是指“提供使用者使用界面”的软件(命令解析器)。它类似于DOS下的command.com和后来的cmd.exe。它接收用户命令,然后调用相应的应用程序。

基本上shell分两大类:
一:图形界面shell(Graphical User Interface shell 即 GUI shell)
例如:应用最为广泛的 Windows Explorer (微软的windows系列操作系统),还有也包括广为人知的 Linux shell,其中 linux shell 包括 X window manager (BlackBox和FluxBox),以及功能更强大的CDE、GNOME、KDE、 XFCE。
二:命令行式shell(Command Line Interface shell ,即CLI shell)
因此,在python解释器的命令行就是shell,在pyCharm中python console就是

二、看例子

#  hello.py

import os                    #操作系统模块
from flask import Flask, render_template, session, redirect, url_for        #引入Flask类、render_templdate函数,session类等
from flask_bootstrap import Bootstrap                                        #引入Bootstrap类
from flask_moment import Moment                                               
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_mail import Mail, Message

basedir = os.path.abspath(os.path.dirname(__file__))                        #当前文件所在的绝对路径

app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'                            #Flask-wtf需要的配置
app.config['SQLALCHEMY_DATABASE_URI'] =\                                     #Flask-SQLAlchemy需要的配置
    'sqlite:///' + os.path.join(basedir, 'data.sqlite')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False                        #Flask-SQLAlchemy需要的配置
app.config['MAIL_SERVER'] = 'smtp.sina.com'                        #Flask-Mail需要的配置:邮件服务器地址
app.config['MAIL_PORT'] = 587                                      #Flask-Mail需要的配置:网络端口
app.config['MAIL_USE_TLS'] = True                                    #Flask-Mail需要的配置:是否开启TLS
app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME')        #Flask-Mail需要的配置:邮箱用户名(值从系统环境获取)
app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD')        #Flask-Mail需要的配置:邮箱密码(值从系统环境获取)
app.config['FLASKY_MAIL_SUBJECT_PREFIX'] = '[Flasky]'                #Flask-Mail需要的配置:邮件主题
app.config['FLASKY_MAIL_SENDER'] = 'Flasky Admin <hello_tincer@sina.com>' #Flask-Mail需要的配置:发件人
app.config['FLASKY_ADMIN'] = os.environ.get('FLASKY_ADMIN')                #Flask-Mial需要的配置:收件人地址

bootstrap = Bootstrap(app)
moment = Moment(app)
db = SQLAlchemy(app)
migrate = Migrate(app, db)
mail = Mail(app)


class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    users = db.relationship('User', backref='role', lazy='dynamic')

    def __repr__(self):
        return '<Role %r>' % self.name


class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True, index=True)
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

    def __repr__(self):
        return '<User %r>' % self.username


def send_email(to, subject, template, **kwargs):
    msg = Message(app.config['FLASKY_MAIL_SUBJECT_PREFIX'] + ' ' + subject,
                  sender=app.config['FLASKY_MAIL_SENDER'], recipients=[to])
    msg.body = render_template(template + '.txt', **kwargs)
    msg.html = render_template(template + '.html', **kwargs)
    mail.send(msg)


class NameForm(FlaskForm):
    name = StringField('What is your name?', validators=[DataRequired()])
    submit = SubmitField('Submit')


@app.shell_context_processor
def make_shell_context():
    return dict(db=db, User=User, Role=Role)


@app.errorhandler(404)
def page_not_found(e):
    return render_template('404.html'), 404


@app.errorhandler(500)
def internal_server_error(e):
    return render_template('500.html'), 500


@app.route('/', methods=['GET', 'POST'])
def index():
    form = NameForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.name.data).first()
        if user is None:
            user = User(username=form.name.data)
            db.session.add(user)
            db.session.commit()
            session['known'] = False
            if app.config['FLASKY_ADMIN']:
                send_email(app.config['FLASKY_ADMIN'], 'New User',
                           'mail/new_user', user=user)
        else:
            session['known'] = True
        session['name'] = form.name.data
        return redirect(url_for('index'))
    return render_template('index.html', form=form, name=session.get('name'),
                           known=session.get('known', False))

print('hello')

if __name__=='__main__':
    app.run()

来看:

#  hello.py

def send_email(to, subject, template, **kwargs):
    msg = Message(app.config['FLASKY_MAIL_SUBJECT_PREFIX'] + ' ' + subject,
                  sender=app.config['FLASKY_MAIL_SENDER'], recipients=[to])
    msg.body = render_template(template + '.txt', **kwargs)
    msg.html = render_template(template + '.html', **kwargs)
    mail.send(msg)

构造好Message的实例msg,再设置body和html属性,最后调用Mail的实例的send()就可以直接发送 。

Mail对应于邮箱:服务器地址、用户名、密码、网络端口、是否使用TLS或SSL等参数,都在mail =Mail(app)构造时设置了。

Message对应于邮件:邮件主题、发送方(name <name@xxx.com>的固定格式)、收件人地址、邮件纯文本、邮件富文本需要要实例msg设置。

最后调用mail.send()方法发送。


三、异步发送邮件

1、多线程发送邮件

def send_async_email(app,msg):
    with app.app_context():                     #调用app.app_context()方法,激活程序上下文
        mail.send(msg)                          #mail.send()需要激活程序上下文current_app(在不同线程中,程序上下文要使用app.current_app()人工创建)

def send_email(to, subject, template, **kwargs):
    msg = Message(app.config['FLASKY_MAIL_SUBJECT_PREFIX'] + ' ' + subject,
                  sender=app.config['FLASKY_MAIL_SENDER'], recipients=[to])
    msg.body = render_template(template + '.txt', **kwargs)
    msg.html = render_template(template + '.html', **kwargs)
    thr = Thread(target=send_async_email,args=[app,msg])
    thr.start()                                #让另一个线程去发送邮件,程序接着往下走
    return thr

mail.send()需要激活程序上下文current_app(在不同线程中,程序上下文要使用app.current_app()人工创建)

这样改完之后,客户端不需要等待,可以直接看到页面。因为,最耗时间的发送邮件步骤由后台的其他线程去执行了。

2、多进程发送邮件

本想试试:使用多进程实现异步发送邮件

# hello.py

from multiprocessing import Process
def send_email(to, subject, template, **kwargs):
    msg = Message(app.config['FLASKY_MAIL_SUBJECT_PREFIX'] + ' ' + subject,
                  sender=app.config['FLASKY_MAIL_SENDER'], recipients=[to])
    msg.body = render_template(template + '.txt', **kwargs)
    msg.html = render_template(template + '.html', **kwargs)
    thr = Process(target=send_async_email,args=[app,msg])
    thr.start()                                #让另一个线程去发送邮件,程序接着往下走
    return thr

出现了EOFError:文件尾错误

3、协程异步发送邮件

# hello.py

import asyncio
@asyncio.coroutine
def use_asyncio_send_email(to, subject, template, **kwargs):
    msg = Message(app.config['FLASKY_MAIL_SUBJECT_PREFIX'] + ' ' + subject,
                  sender=app.config['FLASKY_MAIL_SENDER'], recipients=[to])
    msg.body = render_template(template + '.txt', **kwargs)
    msg.html = render_template(template + '.html', **kwargs)
    a = yield from mail.send(msg)
    return a
@app.route('/', methods=['GET', 'POST'])
def index():
    form = NameForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.name.data).first()
        if user is None:
            user = User(username=form.name.data)
            db.session.add(user)
            db.session.commit()
            session['known'] = False
            if app.config['FLASKY_ADMIN']:
                # send_email(app.config['FLASKY_ADMIN'], 'New User',
                #            'mail/new_user', user=user)
                loop = asyncio.get_event_loop()
                loop.run_until_complete(use_asyncio_send_email(app.config['FLASKY_ADMIN'], 'New User','mail/new_user', user=user))
                loop.close()
        else:
            session['known'] = True
        session['name'] = form.name.data
        return redirect(url_for('index'))
    return render_template('index.html', form=form, name=session.get('name'),
                           known=session.get('known', False))

错误分析:mail.send(msg)  没有返回值(即None),yield from 后面必须要跟一个generator(Iterable 可迭代的)。因此,出现此错误 。










  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值