2016-10-30 6 views
4

내 플라스크 프로젝트는 Flask-Cookiecutter을 기반으로하므로 전자 메일을 비동기 적으로 보내야합니다.Flask-Mail - Flask-Cookiecutter를 기반으로 전자 메일을 비동기 적으로 보냅니다.

전자 메일을 보내기위한 기능은 Miguel’s Tutorial으로 구성되었으며 동 기적으로 작동하는 것은 정상적으로 작동하지만 잘 모릅니다. 비동기 적으로 보낼 수 있도록 수정합니다. 내 로컬 호스트하고 명령을 시작 년대에 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

좋아, 난 내가 다른 개발자 여기를 게시 내 질문에 대한 해결책을 발견 :

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

이동 이메일 전송 기능 :

내가 파일을 만듭니다 : email.py을 코드로

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

@ shefget-리카 :

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) 

그리고 이메일을 보내는 모듈에

은이 같은 것이다 주셔서 감사합니다 답변을하지만, 콘솔은 여전히 ​​메시지를 보여 애플리케이션 컨텍스트의 작업을 외부. 그 동안 나는 correcnt 솔루션을 찾습니다. 다른 개발자를 위해 게시 할 예정입니다. – lukassliacky

4

app = Flask(__name__)을 응용 프로그램 팩터에서 이동하여 모듈 레벨에 배치 할 수 있습니다. 이렇게하면 응용 프로그램 컨텍스트와 함께 응용 프로그램 인스턴스를 스레드로 전달하여 전자 메일을 보낼 수 있습니다. 순환 종속성을 방지하기 위해 다른 영역에서 일부 가져 오기를 변경해야하지만 너무 나쁘지 않아야합니다.

Flask-Mail 및 Flask-RESTful을 사용하는 example of how you can do this입니다. 또한 이것을 테스트하기 위해 pytest를 사용하는 방법을 보여줍니다.

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) 
관련 문제