Flask-security: Document send_mail_task

Created on 12 Dec 2013  路  11Comments  路  Source: mattupstate/flask-security

I was hoping to make my app faster at sending confirmation emails when I noticed this in the code. Could you add a bit of explanation as to how to use this? I assume it has something to do with celery.

Most helpful comment

@erwagasore @joaobarbosa @eriktaubeneck

If you are going to use factory method, recursion error will raise if it is not used properly. Here is the example based on author's example for reference. The trick is using the state object returned by init_app for setting cutomized mail sending function. The author has explained it here and here in #141.

from celery import Celery
from flask import Flask
from flask_security import Security, .. datastore stuff ..
from flask_mail import Mail

celery = Celery()
mail = Mail()
security = Security()

def create_app():
    """Initialize Flask instance."""
    app = Flask(__name__)
    mail.init_app(app)
    security_ctx = security.init_app(app,..datastore stuff..)

    @celery.task
    def send_flask_mail(msg):
        mail.send(msg)

    # Flexible way for define custom mail sending function.
    @security_ctx.send_mail_task
    def delay_flask_security_mail(msg):
        send_flask_mail.delay(msg)

    # You can also define like this as shortcurt
    security_ctx.send_mail_task(send_flask_mail.delay)

    return app

But it looks like the default serializer is JSON (at least in Celery 4.0) and flask_mail.Message can not be jsonified and then passed into Celery. So actually your custom email sending function might be like this:

from flask_mail import Message

@celery.task
def send_flask_mail(**kwargs):
        mail.send(Message(**kwargs))

@security_ctx.send_mail_task
def delay_flask_security_mail(msg):
    send_flask_mail.delay(subject=msg.subject, sender=msg.sender,
                          recipients=msg.recipients, body=msg.body,
                          html=msg.html)

All 11 comments

You likely want to use this. If you are using celery, you could create a task with this snippet:

``` .py
from app import celery #import from where you create your celery object
from flask.ext.security import confirmable

@celery.task()
def send_email_confirmation(user):
confirmable.send_confirmation_instructions(user)
```

To speed up the send time, you'll want to dedicate more resources to that task. The celery docs are quite useful to help you figure out what to do for your setup.

Oh, I just create the task myself? I was assuming there was some purpose to the code I pointed at.

So the function that contains the line you point to is just a function for sending mail arbitrarily using Flask-Security. The line you points to refers to an attribute on the base security object you can override the function which actually does the mail sending. This would be useful, for example, with the above use case with celery. Without the attribute set, you run

.py mail = current_app.extensions.get('mail') mail.send(msg)

you could change this by somewhere using a decorator as it is done in the tests. This would allow you to instead call mail._send.delay(msg), if you created such a task.

This would be an alternate setup to the one proposed above.

Hey guys, if you want to use Celery to send Flask-Security emails, you'll do something like this (pseudo code):

from celery import Celery
from flask import Flask
from flask_security import Security, .. datastore stuff ..
from flask_mail import Mail

celery = Celery()
app = Flask(__name__)
mail = Mail(app)
security = Security(app, .. datastore stuff ..)

@celery.task
def send_flask_mail(msg):
    mail.send(msg)

@security.send_mail_task
def delay_flask_security_mail(msg):
    send_flask_mail.delay(msg)
from app.factory import create_celery_app, mail, security

celery = create_celery_app()

@celery.task()
def send_security_mail(msg):
    mail.send(msg)

@security.send_mail_task
def delay_security_mail(msg):
    send_security_mail.delay(msg)

@mattupstate, based on the code above I am getting a RuntimeError: maximum recursion depth exceeded when I run celery celery worker -A app.tasks -l INFO

@erwagasore did you managed to fix it? I'm having the same issue :cry:

I think this is likely the same issue described in issue 340.

Thanks @eriktaubeneck!

@erwagasore @joaobarbosa @eriktaubeneck

If you are going to use factory method, recursion error will raise if it is not used properly. Here is the example based on author's example for reference. The trick is using the state object returned by init_app for setting cutomized mail sending function. The author has explained it here and here in #141.

from celery import Celery
from flask import Flask
from flask_security import Security, .. datastore stuff ..
from flask_mail import Mail

celery = Celery()
mail = Mail()
security = Security()

def create_app():
    """Initialize Flask instance."""
    app = Flask(__name__)
    mail.init_app(app)
    security_ctx = security.init_app(app,..datastore stuff..)

    @celery.task
    def send_flask_mail(msg):
        mail.send(msg)

    # Flexible way for define custom mail sending function.
    @security_ctx.send_mail_task
    def delay_flask_security_mail(msg):
        send_flask_mail.delay(msg)

    # You can also define like this as shortcurt
    security_ctx.send_mail_task(send_flask_mail.delay)

    return app

But it looks like the default serializer is JSON (at least in Celery 4.0) and flask_mail.Message can not be jsonified and then passed into Celery. So actually your custom email sending function might be like this:

from flask_mail import Message

@celery.task
def send_flask_mail(**kwargs):
        mail.send(Message(**kwargs))

@security_ctx.send_mail_task
def delay_flask_security_mail(msg):
    send_flask_mail.delay(subject=msg.subject, sender=msg.sender,
                          recipients=msg.recipients, body=msg.body,
                          html=msg.html)

@jxltom we are using similar solution as you have presented in https://github.com/mattupstate/flask-security/issues/194#issuecomment-278554575. Would you mind extending the documentation with your example?

@jirikuncar Sure, will do that.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mafrosis picture mafrosis  路  6Comments

asmodehn picture asmodehn  路  6Comments

swedishmike picture swedishmike  路  5Comments

HarrySky picture HarrySky  路  4Comments

joeyespo picture joeyespo  路  3Comments