2012-06-15 5 views
2

Я отправляю письма из своего приложения Flask с расширением Flask-Mail. Он запускает метод send() синхронно, и я должен ждать, пока он отправит сообщение. Как я могу запустить его в фоновом режиме?Асинхронный запуск Flask-Mail

+4

Возможный дубликат [это] (http://stackoverflow.com/questions/10003933/whats-the-proper-way-to-run-some-python-code-asynchronously) – Enrico

ответ

7

Это не так сложно - вам нужно отправить почту в другой поток, так что вы не будете блокировать основной поток. Но есть один трюк.

Вот мой код, который делает шаблон, создание почтового тела, и позволяет отправлять его как синхронно, так и асинхронно:

mail_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 будет вызывать контекст при вызове функции.

Чтобы использовать этот код вам также необходимо инициализировать mail объект с приложением Колба:

run.py

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

Действительно полезный! благодаря! –

0

Я хотел бы, чтобы упростить код 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 "[email protected]") 


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