Flask-mail send_async_email() 生成异常和 RunTimeError:在应用程序上下文之外工作

问题描述

除了 send_email() 之外,其他一切都有效。无论我使用 const matchSlugs6 = (name) => (posts) => map ( prop('node'),filter ( compose (any (propEq ('slug',name)),path (['node','categories'])),posts ) ) 还是远程主机,我都会遇到相同的异常。我的猜测是我没有在正确的地方推送上下文,但我已经盯着这个看了很长时间,我显然没有看到错误。任何帮助将不胜感激!

__init__.py:

localhost

views.py:

from flask import Flask,Blueprint,jsonify,...

from config import config
from flask_login import LoginManager
from extensions import db,mail,moment

login_manager = LoginManager()
login_manager.login_view = 'auth.login'

def create_app():  
    app = Flask(__name__,static_url_path='',static_folder='../app/static',template_folder='../app/templates')

    app.config.from_object(config['default'])
    config['default'].init_app(app)
    
    db.init_app(app)
    mail.init_app(app)
    moment.init_app(app)

    with app.app_context():
        db.create_all()

    migrate = Migrate(app,db)
    from app import models
    
    from .templates.auth import auth_bp
    from .templates.main import main_bp

    app.register_blueprint(main_bp)
    app.register_blueprint(auth_bp,url_prefix='/auth')

    login_manager.init_app(app)

    return app

email.py:

from flask import abort,flash,...
from flask.globals import current_app
from flask_login import current_user,login_required,login_user,logout_user
from werkzeug.security import generate_password_hash
from datetime import datetime,timezone

from wtforms.validators import UUID

from . import auth_bp

from extensions import db,common_context
from app.models. ...
from .forms import LoginForm,RegistrationForm,...
from .email import send_email

@auth_bp.route('/register/',methods=['GET','POST'],defaults={'user_id': None})
def register(user_id):
    from sqlalchemy.exc import IntegrityError
    from .email import send_email

    if current_user.is_authenticated:
        return redirect(url_for('main.home'))
    form=RegistrationForm()

    if form.validate_on_submit():
        try:
            individual = Individual(...
            )
            db.session.add(individual)
            db.session.flush()

            individual_email = Individual_email(...
            )
            db.session.add(individual_email)

            user = User(...
            )
            db.session.add(user)
            db.session.commit()
            token = user.generate_confirmation_token()
            # with current_app.app_context():
            #     print(individual_email.email,user,individual.first_name,token) - this works!!!
            send_email(individual_email.email,'Please Confirm Your Account','auth/email/confirm',user=user,token=token,individual=individual)
            flash('A confirmation email has been sent to you by email.')
        except AssertionError as err:
            db.session.rollback()
            abort(409,err) 
        except IntegrityError as err:
            db.session.rollback()
            abort(409,err.orig) 
        except Exception as err:
            db.session.rollback()
            abort(500,err)
        finally:
            db.session.close()
        return redirect(url_for('auth.login'))
    
    context = {
        'form': form,'title': 'Registration',}
    return render_template('auth/register.html',**context,**common_context)

配置:

from flask import render_template,current_app
from flask_mail import Message
from threading import Thread
from app import mail

def send_async_email(app,msg):
    with app.app_context():
        mail.send(msg)

def send_email(to,subject,template,**kwargs):
    app=current_app
    msg = Message(app.config['MAIL_SUBJECT_PREFIX'] + subject,sender = app.config['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

输出

import os

from dotenv import load_dotenv

basedir = os.path.abspath(os.path.dirname(__file__))
load_dotenv(os.path.join(basedir,'.env'))

class Config(object):
    DEBUG = False
    TESTING = False
    CSRF_ENABLED = True

    SECRET_KEY = os.environ.get('SECRET_KEY')
    sqlALCHEMY_TRACK_MODIFICATIONS = False

    ...

    @staticmethod
    def init_app(app):
        pass

class ProductionConfig(Config):
    DEBUG = False
    sqlALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URI')
    MAIL_SERVER = os.environ.get('MAIL_SERVER','smtp.gmail.com')
    MAIL_PORT = int(os.environ.get('MAIL_PORT','587'))
    MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS','true').lower() in \
        ['true','on','1']
    MAIL_USE_SSL = os.environ.get('MAIL_USE_SSL','false').lower()
    MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
    MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
    MAIL_SUBJECT_PREFIX = '[...]'
    MAIL_SENDER = '... <...>'
    MAIL_ADMIN = os.environ.get('MAIL_ADMIN')

class DevelopmentConfig(Config):
    DEVELOPMENT = True
    DEBUG = True
    sqlALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URI')

    MAIL_SERVER = 'localhost'
    MAIL_PORT = 25
    MAIL_USE_TLS = False
    MAIL_USE_SSL = False
    # MAIL_DEBUG = app.debug
    MAIL_USERNAME = '...'
    MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
    MAIL_DEFAULT_SENDER = '... <...>'
    MAIL_MAX_EMAILS = None
    # MAIL_SUPPRESS_SEND = app.testing
    MAIL_ASCII_ATTACHMENTS = False
    MAIL_SUBJECT_PREFIX = '[...]'
    MAIL_SENDER = '... <...>'
    MAIL_ADMIN = '...'

    config = {
    'development': DevelopmentConfig,'testing': TestingConfig,'production': ProductionConfig,'default': DevelopmentConfig
    }

解决方法

main = [ ['I','want','dog'],['driving','a','car'],['S','O','S'] ] leading = iter(['yes','no','yes']) joined = [[next(leading),' '.join(m)] for m in main] import csv with open('output.csv','w') as f: writer = csv.writer(f) writer.writerows(joined) 中的两个函数合二为一以避免上下文问题:

email.py

第一次尝试效果很好。我查看了其他 Stackoverflow 帖子并收到了将 def send_email(to,subject,template,**kwargs): app=current_app with app.app_context(): msg = Message(app.config['MAIL_SUBJECT_PREFIX'] + subject,sender = app.config['MAIL_SENDER'],recipients=[to]) msg.body = render_template(template + '.txt',**kwargs) msg.html = render_template(template + '.html',**kwargs) Thread(target=mail.send(msg)).start() 导入此模块的建议。我建议不要走这条路。我有两个实例,而不是一个或相同的异常,具体取决于 create_app 调用的位置。