2016-10-30 15 views
4

私のフラスコプロジェクトはFlask-Cookiecutterに基づいており、私は電子メールを非同期で送る必要があります。Flask-Mail - Flask-Cookiecutterに基づいて電子メールを非同期で送信しています

メールを送信する機能はMiguel’s Tutorialで設定されていますが、同期送信は正常に動作しますが、非同期に送信するための変更方法はわかりません。私はlocalhostとそれがコマンドで始まる年代にview.py

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

アプリケーションの実行中に

マイapp.py

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

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) 

ルート:

python manage.py server 

私がメールを送信するための関数を呼び出すと、コンソールの出力は次のとおりです。すべての答えを

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. 

感謝。

答えて

2

さて、私は他の人の開発者のためのそれをここに掲示する私の質問のための解決策を見つけた:

私はファイルを作成します。コードでemail.pyを:

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:

... 
from app.email import send_email 
... 

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

http://localhost:5000/mailerに電話するとカウントダウンを開始し、数秒後にメールが送信されます。

+0

ありがとう、この問題もあります。 – Pegasus

2

移動電子メールは、バックグラウンドスレッドへの送信機能:

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 
+0

:あなたの答えに感謝しますが、コンソールはまだメッセージを表示:アプリケーションのコンテキストの外で作業します。その間、私はcorrecnt解決策を見つける。私は他の開発者のためにここに掲載します。 – lukassliacky

4

app = Flask(__name__)をアプリケーションファクトリから移動し、モジュールレベルに配置することができます。これにより、アプリケーションコンテキストを持つアプリインスタンスをスレッドに渡して電子メールを送信できます。循環依存を防ぐために、他の領域の一部のインポートを変更する必要がありますが、それほど悪くはありません。

Flask-MailとFlask-RESTfulを使用するexample of how you can do thisがあります。また、これをテストするためにpytestを使用する方法も示しています。

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) 

や電子メールを送信するためのモジュールで、あなたはこのようなものだろう:shefget-リカ@

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) 
関連する問題