flask-mail icon indicating copy to clipboard operation
flask-mail copied to clipboard

RuntimeError: working outside of application context

Open dtheodor opened this issue 11 years ago • 19 comments

When using the mailer to send an e-mail from a background worker (that is, outside of the Flask application context), it crashes and burns.

dtheodor avatar Feb 05 '14 17:02 dtheodor

This is expected. Flask-Mail requires an application context so that it can read the configuration values. There are two options:

  1. Customize your background worker(s) to create an application context before each task is executed
  2. Create an application context in your task. For example:
@task
def send_email(msg):
    with app.app_context():
        mail.send(msg)

mattupstate avatar Feb 05 '14 17:02 mattupstate

You were quick to close it. I will argue that this is neither expected nor sensible. Flask-mail requires the app object to read configuration values when it is initialized, not at any point in time later. There is only a signal that updates the application on sent e-mail, but that is optional behavior.

After initialization, flask-mail is just a mailer. Instead of littering application code with app.app_context(), I think this should be accommodated by the library.

dtheodor avatar Feb 05 '14 18:02 dtheodor

I was quick to close, I apologize. I see your point now, the code can be adjusted to work outside an app context. However, I think it depends if you use the init_app function or not. At which point the current_app object would have to be used to read configuration values. If you happen to use Mail(app) all will be good.

mattupstate avatar Feb 05 '14 18:02 mattupstate

I will give a pull-request a shot. Unless I am mistaken about Flask internals and looking into the Mail code, both init_app and the Mail() constructor only access the app.config and do not require a current_app to be present.

dtheodor avatar Feb 05 '14 20:02 dtheodor

Hi guys, any suggestion about this issue? using Mail(app) i still got runtime error "working outside of application context"

rizarsyi avatar Apr 06 '14 18:04 rizarsyi

@dtheodor if I recall correctly, this issue is more about Flask itself, not flask-mail. @mattupstate with app.app_context(): works just fine, but it's a bit annoying to write it over and over again. If I'm not mistaken, this problem appears because there is no actual current_app when you are using a background worker. Potential workaround is to to use self.app.app_context() within send function. What do you think?

jackunion avatar Jul 12 '14 20:07 jackunion

I forgot to mention that here should be self.app = app as well.

jackunion avatar Jul 12 '14 20:07 jackunion

I think I'd like to step back and remind everyone that this is a Flask extension. It's designed to be used with Flask. That means the extension must consider the possibility of multiple apps running in the same process. If you're looking for something less tied to Flask you might want to look into other libraries such as Envelopes. You could easily write the glue yourself if you need to tie configuration options on your application to a mail client.

mattupstate avatar Jul 14 '14 16:07 mattupstate

@mattupstate shouldn't one register Mail instance for each app? In this case my solution should work (I guess). At least the section about flask-mail, background workers and possible use of with app.app_context(): mail.send(msg) should be added somewhere in the docs.

jackunion avatar Jul 14 '14 17:07 jackunion

@jackunion you could do that if you like, but Flask extensions should be designed to support multiple apps via the init_app method.

mattupstate avatar Jul 14 '14 17:07 mattupstate

@mattupstate I understand you perfectly. Anyway, it is your decision to merge or not to merge that matters, but I don't see how self.app = app could break support for multiple apps (there already exists self.app = app inside Mail.__init__ but it is never used). Sent you a PR.

jackunion avatar Jul 14 '14 18:07 jackunion

@jackunion Please see http://flask.pocoo.org/docs/extensiondev/, init_app should not bind the extension object to a specific app.

untitaker avatar Jul 19 '14 09:07 untitaker

@untitaker thank you for making this clear.

jackunion avatar Jul 19 '14 11:07 jackunion

could this be done with from flask import current_app ?

jamesonjlee avatar Aug 06 '14 19:08 jamesonjlee

No, current_app requires an app context.

untitaker avatar Aug 06 '14 19:08 untitaker

OK, I'm "dealing with it" and use with app.app_context(): .....

But why is it that DEFAULT_MAIL_SENDER in settings.py does not get recognized:

File "C:\Anaconda\lib\site-packages\flask_mail.py", line 156, in send "The message does not specify a sender and a default sender " AssertionError: The message does not specify a sender and a default sender has not been configured

robertcatgithub avatar Aug 31 '14 22:08 robertcatgithub

That's a totally different issue, but the setting is MAIL_DEFAULT_SENDER.

davidism avatar Sep 01 '14 01:09 davidism

Due to the requirement "one Mail instance and multiple Flask apps all configured through the Mail instance's init_app", I don't think what I had in mind is possible. The Mail object then always needs the current_app to figure out which app (aka mail configuration) it should use. If it is instantiated through Mail(app), it already works without requiring the current_app to be set. You can close the issue as cannot fix as far as I am concerned.

dtheodor avatar May 31 '15 13:05 dtheodor

After six years, But yeah i hope this might hint for other developers.

Thread( target=copy_current_app_context(send_async_email), args=(current_app._get_current_object(), msg), ).start()

We need to use get_current_object().

https://github.com/pgjones/quart/issues/56

TechStuffBoy avatar Jul 03 '20 04:07 TechStuffBoy

You must be inside a context to access current_app. Either you're in a request or a CLI command, in which case this is already true, or you push one manually with app.app_context():. This is a general pattern in Flask and extensions.

davidism avatar May 23 '24 16:05 davidism