Flask - cannot use Flask and Flask-mail instances from other files
Since you are using an application factory you need to use the .init_app
method on the Flask-Mail
class like you did the Flask-SQLAlchemy
class. from application import app
will not work since you are never initializing an instance of the flask application until you call the create_app
function in run.py
application/__init__.py
from flask_mail import Mailmail = Mail()def create_app(config_lvl): # stuff mail.init_app(app) # more stuff return app
Also you can use current_app
to refer to the application instance instead of the instance itself as long as the block of code you use it in is being ran in a flask application. Here is a more in depth explanation.
application/auth/email.py
from application import mail # you can now import the Mail() objectfrom flask_mail import Messagefrom flask import current_app # use this to reference current application contextdef send_email(to, subject, template): msg = Message( subject, recipients=[to], html=template, sender=current_app.config['MAIL_DEFAULT_SENDER'] ) mail.send(msg)
application/auth/token.py
from itsdangerous import URLSafeTimedSerializerfrom flask import current_appdef generate_confirmation_token(email): serializer = URLSafeTimedSerializer(current_app.config['SECRET_KEY']) return serializer.dumps(email, salt=current_app.config['SECURITY_PASSWORD_SALT'])def confirm_token(token, expiration = 600): serializer = URLSafeTimedSerializer(current_app.config['SECRET_KEY']) try: email = serializer.loads( token, salt=current_app.config['SECURITY_PASSWORD_SALT'], max_age=expiration ) except: return False return email
also should note that you don't need from . import auth
in any of your modules under the auth
blueprint except views.py
EDIT
Side note: You don't have to add the user to the session because it was added when you queried for it earlier in the route. I was unaware of this for the longest time myself.
@auth.route('/confirm/<token>')@login_requireddef confirm_email(token): try: email = confirm_token(token) except: flash('The confirmation link is invalid or has expired.', 'danger') user = User.query.filter_by(email=email).first_or_404() if user.confirmed: flash('Account already confirmed. Please login.', 'success') else: user.confirmed = True user.confirmed_on = datetime.datetime.now() # db.session.add(user) # can remove this db.session.commit() flash("You've confirmed your account. Thanks!", 'success') return redirect(url_for('auth.login'))
According to http://flask.pocoo.org/docs/0.12/patterns/appfactories/ you have to use current_app (from flask import current_app) to access your Flask instance for wherever in your application.Then you can use your config variables: current_app.config['DEBUG']
for instance.
Another point to consider when using application factories, create instance class instances outside of the 'create_app()' function. Then you have to use .init_app method:
Below is an example:
from flask_mail import Mailmail= Mail()def create_app(): mail.init_app(app)