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.
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
stateobject returned byinit_appfor setting cutomized mail sending function. The author has explained it here and here in #141.But it looks like the default serializer is JSON (at least in Celery 4.0) and
flask_mail.Messagecan not be jsonified and then passed into Celery. So actually your custom email sending function might be like this: