Search code examples
asynchronousflaskflask-securityflask-mail

Sending async email with Flask-Security


I'm attempting to configure Flask-Security to send email asynchronously.

I have some code which send async email via Flask-Mail, but I'm having trouble integrating it with my application factory function so that it works in conjunction with Flask-Security.

Application factory:

mail = Mail()
db = SQLAlchemy()
security = Security()

from app.models import User, Role
user_datastore = SQLAlchemyUserDatastore(db, User, Role)

def create_app(config_name):
    # Config
    app = Flask(__name__)
    app.config.from_object(config[config_name])
    config[config_name].init_app(app)

    # Initialize extensions
    mail.init_app(app)
    db.init_app(app)
    security.init_app(app, user_datastore)

    return app

In the Flask-Security documentation it says to use @security.send_mail_task to override the way the extension sends emails.

So where exactly do I implement this decorator? Seems like anywhere I put it inside the application factory, I get circular imports.

These are the async email functions I am trying to use, taken from this issue:

@async
def send_security_email(msg):
    with app.app_context():
       mail.send(msg)

@security.send_mail_task
def async_security_email(msg):
    send_security_email(msg)

Where does this code need to be put in order to work with the app factory?

Thanks in advance.


Solution

  • I was able to achieve this like so:

    mail = Mail()
    db = SQLAlchemy()
    security = Security()
    
    from app.models import User, Role
    user_datastore = SQLAlchemyUserDatastore(db, User, Role)
    
    def create_app(config_name):
        # Config
        app = Flask(__name__)
        app.config.from_object(config[config_name])
        config[config_name].init_app(app)
    
        # Initialize extensions
        mail.init_app(app)
        db.init_app(app)
        security_ctx = security.init_app(app, user_datastore)
    
        # Send Flask-Security emails asynchronously
        @security_ctx.send_mail_task
        def async_security_email(msg):
            send_security_email(app, mail, msg)
    
        return app