【问题标题】:Run Flask-Mail asynchronously异步运行 Flask-Mail
【发布时间】:2012-06-15 08:42:30
【问题描述】:

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

【问题讨论】:

  • this的可能重复

标签: python email flask


【解决方案1】:

它没有那么复杂——你需要在另一个线程中发送邮件,所以你不会阻塞主线程。但是有一个技巧。

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

ma​​il_sender.py

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

app = Flask('app')
mail_sender.mail.init_app(app)

【讨论】:

    【解决方案2】:

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

    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()
    

    【讨论】:

      【解决方案3】:

      使用Flask-Executor。完全公开,我自己写的就是为了解决这个确切的问题。

      为什么?

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

      它是这样的:

      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 函数就像运行常规内联逻辑一样,并将其提交给执行程序。无论您发送多少电子邮件,只会运行执行程序中定义的最大线程数(默认为 5* 数量的 CPU 内核),并且对send_email 的请求中的任何溢出都将排队。

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

      【讨论】:

      • 这段代码对我来说会发生什么,有时我会收到一封电子邮件,有时却没有
      猜你喜欢
      • 2017-03-12
      • 2016-03-02
      • 2017-04-11
      • 1970-01-01
      • 1970-01-01
      • 2012-04-15
      • 1970-01-01
      • 1970-01-01
      • 2021-09-23
      相关资源
      最近更新 更多