首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >异步运行Flask-Mail

异步运行Flask-Mail
EN

Stack Overflow用户
提问于 2012-06-15 16:42:30
回答 3查看 4K关注 0票数 3

我正在使用Flask-Mail扩展从我的Flask应用程序发送电子邮件。它同步运行send()方法,我必须等到它发送消息。怎样才能让它在后台运行?

EN

回答 3

Stack Overflow用户

发布于 2013-08-24 00:17:00

这并不复杂-你需要在另一个线程中发送邮件,所以你不会阻塞主线程。但有一个诀窍。

下面是我的代码,它呈现模板,创建邮件正文,并允许同步和异步发送它:

mail_sender.py

代码语言:javascript
复制
import threading
from flask import render_template, copy_current_request_context, current_app
from flask_mail import Mail, Message

mail = Mail()

def create_massege(to_email, subject, template, from_email=None, **kwargs):
    if not from_email:
        from_email = current_app.config['ROBOT_EMAIL']
    if not to_email:
        raise ValueError('Target email not defined.')
    body = render_template(template, site_name=current_app.config['SITE_NAME'], **kwargs)
    subject = subject.encode('utf-8')
    body = body.encode('utf-8')
    return Message(subject, [to_email], body, sender=from_email)

def send(to_email, subject, template, from_email=None, **kwargs):
    message = create_massege(to_email, subject, template, from_email, **kwargs)
    mail.send(message)

def send_async(to_email, subject, template, from_email=None, **kwargs):
    message = create_massege(to_email, subject, template, from_email, **kwargs)

    @copy_current_request_context
    def send_message(message):
        mail.send(message)

    sender = threading.Thread(name='mail_sender', target=send_message, args=(message,))
    sender.start()

请注意@copy_current_request_context装饰器。这是必需的,因为Flask-Mail的内部使用了请求上下文。如果我们在新的线程中运行它,上下文将会丢失。我们可以用@copy_current_request_context来阻止这种装饰函数--当函数被调用时,Flask会推送上下文。

要使用此代码,您还需要使用Flask应用程序初始化mail对象:

run.py

代码语言:javascript
复制
app = Flask('app')
mail_sender.mail.init_app(app)
票数 9
EN

Stack Overflow用户

发布于 2018-10-13 13:16:08

使用Flask-Executor。坦率地说,我自己写它就是为了解决这个问题。

为什么?

  1. 使用concurrent.futures设置线程池,而不是手动管理线程,可防止创建任意数量的线程。相反,使用预定义的线程池来运行从队列馈送的作业。
  2. Flask-Executor提供了包含当前请求上下文和当前应用上下文的已提交任务,因此您不需要编写任何处理代码来管理此

它看起来是这样的:

代码语言:javascript
复制
from flask import Flask, current_app
from flask_executor import Executor
from flask_mail import Mail, Message

app = Flask(__name__)
# Set email server/auth configuration in app.config[]

executor = Executor(app)
mail = Mail(app)


def send_email(to, subject, message_text, message_html):
    msg = Message(subject, sender=current_app.config['MAIL_USERNAME'], recipients=[to])
    msg.body = message_text
    msg.html = message_html
    mail.send(msg)


@app.route('/signup')
def signup():
    # My signup form logic
    future = executor.submit(send_email, 'recipient@example.com', 'My subject', 'My text message', '<b>My HTML message</b>')
    print(future.result())
    return 'ok'

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

基本上,编写send_email函数就像运行常规的内联逻辑一样,并将其提交给executor。无论您发送多少电子邮件,只有在executor中定义的最大线程数(默认情况下为5* CPU核心数)将运行,并且对send_email的请求中的任何溢出都将被排队。

总体而言,您的代码保持整洁,并且不需要为要运行的每个异步函数编写一堆包装器代码。

票数 2
EN

Stack Overflow用户

发布于 2017-11-09 00:37:36

我想简化Marboni的代码,所以看看这里。

代码语言:javascript
复制
import threading

from flask import copy_current_request_context
from flask_mail import Message
from app import app, mail


def create_message(recipient, subject, body):

    if not recipient:
        raise ValueError('Target email not defined.')

    subject = subject.encode('utf-8')
    body = body.encode('utf-8')

    return Message(subject, [recipient], body, sender=app.config['MAIL_USERNAME'] or "groundifly@gmail.com")


def send_async(recipient, subject, body):

    message = create_message(recipient, subject, body)

    @copy_current_request_context
    def send_message(message):
        mail.send(message)

    sender = threading.Thread(name='mail_sender', target=send_message, args=(message,))
    sender.start()
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11047307

复制
相关文章

相似问题

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