[docs]defsend_email(**kwargs:object)->None:"""Send a threaded email. Without threading the app will wait until the email has been sent before continuing. In order to access the application context for this function a protected ``werkzeug`` attribute has to be accessed. From https://blog.miguelgrinberg.com/post/ ``the-flask-mega-tutorial-part-xv-a-better-application-structure``: Using current_app directly in the send_async_email() function that runs as a background thread would not have worked, because current_app is a context-aware variable that is tied to the thread that is handling the client request. In a different thread, current_app would not have a value assigned. Passing current_app directly as an argument to the thread object would not have worked either, because current_app is really a proxy object that is dynamically mapped to the application instance. So passing the proxy object would be the same as using current_app directly in the thread. What I needed to do is access the real application instance that is stored inside the proxy object, and pass that as the app argument. The current_app._get_current_object() expression extracts the actual application instance from inside the proxy object, so that is what I passed to the thread as an argument. Note: Keyword args (dict) to pass to ``attachments``: See ``flask_mail.Message.attach``. * filename: filename of attachment * content_type: file mimetype * data: the raw file data :param kwargs: Keyword args to pass to ``Message``: See ``flask_mail.Message``. """# noinspection PyProtectedMember# pylint: disable=protected-accessapp=current_app._get_current_object()# type: ignoresubject_prefix=app.config["MAIL_SUBJECT_PREFIX"]subject=kwargs.get("subject","")kwargs["subject"]=f"{subject_prefix}{subject}"kwargs["sender"]=kwargs.get("sender",app.config["DEFAULT_MAIL_SENDER"])message=Message(**kwargs)thread=Thread(target=_send_async_email,args=(app,message))thread.start()