首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >烧瓶-邮件-异步发送电子邮件,基于烧瓶-库克

烧瓶-邮件-异步发送电子邮件,基于烧瓶-库克
EN

Stack Overflow用户
提问于 2016-10-30 06:44:18
回答 3查看 7.8K关注 0票数 6

我的烧瓶项目是基于烧瓶-炊具的,我需要异步发送电子邮件。

发送电子邮件的函数是由米格尔教程配置的,并且同步发送很好,但我不知道如何修改它以异步发送。

我的app.py

代码语言:javascript
复制
def create_app(config_object=ProdConfig):
    app = Flask(__name__)
    app.config.from_object(config_object)
    register_extensions(app)
    register_blueprints(app)
    register_errorhandlers(app)
    return app

def register_extensions(app):
    assets.init_app(app)
    bcrypt.init_app(app)
    cache.init_app(app)
    db.init_app(app)
    login_manager.init_app(app)
    debug_toolbar.init_app(app)
    migrate.init_app(app, db)
    mail.init_app(app)
    return None

我的view.py

代码语言:javascript
复制
from flask import current_app

@async
def send_async_email(current_app, msg):
    with current_app.app_context():
        print('##### spustam async')
        mail.send(msg)


# Function for sending emails
def send_email(to, subject, template, **kwargs):
    msg = Message(subject, recipients=[to])
    msg.html = render_template('emails/' + template, **kwargs)
    send_async_email(current_app, msg)

view.py中的路由

代码语言:javascript
复制
@blueprint.route('/mailer', methods=['GET', 'POST'])
def mailer():
    user = current_user.full_name
    send_email(('name@gmail.com'),
               'New mail', 'test.html',
               user=user)
    return "Mail has been send."

应用程序在我的本地主机中运行,它以命令开头

代码语言:javascript
复制
python manage.py server

当我调用函数发送邮件时,控制台中的输出是:

代码语言:javascript
复制
RuntimeError: Working outside of application context.

This typically means that you attempted to use functionality that needed
to interface with the current application object in a way.  To solve
this set up an application context with app.app_context().  See the
documentation for more information.

谢谢你的回答。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-10-30 12:26:50

好的,我为我的问题找到了解决方案--我在这里为其他开发人员张贴了它:

我用代码创建了文件: email.py:

代码语言:javascript
复制
from threading import Thread
from flask import current_app, render_template
from flask_mail import Message
from .extensions import mail
from time import sleep    

def send_async_email(app, msg):
    with app.app_context():
        # block only for testing parallel thread
        for i in range(10, -1, -1):
            sleep(2)
            print('time:', i)
        print('====> sending async')
        mail.send(msg)

def send_email(to, subject, template, **kwargs):
    app = current_app._get_current_object()
    msg = Message(subject, recipients=[to])
    msg.html = render_template('emails/' + template, **kwargs)
    thr = Thread(target=send_async_email, args=[app, msg])
    thr.start()
    return thr

我的view.py:

代码语言:javascript
复制
...
from app.email import send_email
...

@blueprint.route('/mailer', methods=['GET', 'POST'])
def mailer():
    user = current_user.full_name
    send_email(('name@gmail.com'),
               'New mail', 'test.html',
               user=user)
    return "Mail has been send."

当我打电话给http://localhost:5000/mailer时,它开始倒计时,几秒钟后,邮件就被发送了。

票数 13
EN

Stack Overflow用户

发布于 2016-10-30 11:23:14

将电子邮件发送功能移动到后台线程:

代码语言:javascript
复制
from threading import Thread

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

def send_email(to, subject, template, **kwargs):
       msg = Message(subject, recipients=[to])
       msg.html = render_template('emails/' + template, **kwargs)
       thr = Thread(target=send_async_email,args=[app,msg])
       thr.start()
       return thr
票数 4
EN

Stack Overflow用户

发布于 2017-02-05 00:28:15

您可以将app = Flask(__name__)移出应用程序工厂,并将其放置在模块级别。这允许您将带有其应用程序上下文的应用实例传递到您的线程中,以便发送电子邮件。您可能需要更改其他领域的一些导入,以防止循环依赖,但这应该不会太糟糕。

这里是一个使用如何做到这一点的例子的烧杯邮件和烧瓶-RESTful。它还展示了如何使用pytest来测试这一点。

代码语言:javascript
复制
from flask import Flask

from .extensions import mail
from .endpoints import register_endpoints
from .settings import ProdConfig

# app context needs to be accessible at the module level
# for the send_message.send_
app = Flask(__name__)


def create_app(config=ProdConfig):
    """ configures and returns the the flask app """
    app.config.from_object(config)

    register_extensions()
    register_endpoints(app)

    return app


def register_extensions():
    """ connects flask extensions to the app """
    mail.init_app(app)

在你发送电子邮件的模块里,你会看到这样的东西:

代码语言:javascript
复制
from flask_mail import Message

from app import app
from app import mail
from utils.decorators import async_task


def send_email(subject, sender, recipients, text_body, html_body=None, **kwargs):
    app.logger.info("send_email(subject='{subject}', recipients=['{recp}'], text_body='{txt}')".format(sender=sender, subject=subject, recp=recipients, txt=text_body))
    msg = Message(subject, sender=sender, recipients=recipients, **kwargs)
    msg.body = text_body
    msg.html = html_body

    app.logger.info("Message(to=[{m.recipients}], from='{m.sender}')".format(m=msg))
    _send_async_email(app, msg)


@async_task
def _send_async_email(flask_app, msg):
    """ Sends an send_email asynchronously
    Args:
        flask_app (flask.Flask): Current flask instance
        msg (Message): Message to send
    Returns:
        None
    """
    with flask_app.app_context():
        mail.send(msg)

(2019年评论)

注意:我在几年前发布了这篇文章,我觉得在应用工厂之外实例化烧瓶对象并不理想。send_email函数需要一个烧瓶实例才能工作,但是您可以在该函数中实例化一个新的烧瓶应用程序(不要忘记您的配置)。

我猜想current_app可能也能工作,但我觉得这可能会产生副作用,因为它需要创建一个新的应用程序上下文--在当前的应用程序上下文中,似乎是错误的,但可能有效。

一个很好的选择是:查看芹菜并使用RabbitMQ作为后端。

对于较大的应用程序或卷,您可能会考虑通过message (如RabbitMQ )将电子邮件发送到另一个应用程序。查看事件驱动的设计模式。如果您有需要邮寄服务的多个应用程序,这可能是很有吸引力的。如果您的服务需要支持审计日志、交付恢复等,这可能会很好。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40326651

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档