RuntimeError: Working outside of application contex. I'm having problem working with scheduler and Flask-Mail

68 Views Asked by At

I'm trying to send an email at a specific date witn Flask-Mail and scheduler. I can send a mail with Flask-Mail, but after incorporating scheduler it give me some problems like this:

INFO:apscheduler.executors.default:Running job "send_scheduled_email (trigger: date[2023-08-17 09:02:00 -04], next run at: 2023-08-17 09:02:00 -04)" (scheduled at 2023-08-17 09:02:00-04:00) INFO:apscheduler.scheduler:Removed job b856552abf324232a258cf59c161bbe8 DEBUG:apscheduler.scheduler:No jobs; waiting until a job is added DEBUG:root:Sending scheduled email ERROR:apscheduler.executors.default:Job "send_scheduled_email (trigger: date[2023-08-17 09:02:00 -04], next run at: 2023-08-17 09:02:00 -04)" raised an exception Traceback (most recent call last): File "C:\Users\Snatk\TimFlask\venv\Lib\site-packages\apscheduler\executors\base.py", line 125, in run_job retval = job.func(*job.args, **job.kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\Snatk\TimFlask\website\views.py", line 64, in send_scheduled_email mail.send(msg) File "C:\Users\Snatk\TimFlask\venv\Lib\site-packages\flask_mail.py", line 491, in send with self.connect() as connection: ^^^^^^^^^^^^^^ File "C:\Users\Snatk\TimFlask\venv\Lib\site-packages\flask_mail.py", line 508, in connect return Connection(app.extensions['mail']) ^^^^^^^^^^^^^^ File "C:\Users\Snatk\TimFlask\venv\Lib\site-packages\werkzeug\local.py", line 311, in __get__ obj = instance._get_current_object() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\Snatk\TimFlask\venv\Lib\site-packages\werkzeug\local.py", line 508, in _get_current_object raise RuntimeError(unbound_message) from None RuntimeError: Working outside of application context.

This typically means that you attempted to use functionality that needed the current application. To solve this, set up an application context with app.app_context(). See the documentation for more information.

init.py

from flask import Flask
from flask import request 
from flask_sqlalchemy import SQLAlchemy
from os import path
from flask_login import LoginManager
from flask_mail import Mail
from apscheduler.schedulers.background import BackgroundScheduler

mail = Mail()
db = SQLAlchemy()
DB_NAME = "database.db"
scheduler = BackgroundScheduler()


def create_app():
    app = Flask(__name__)
    app.config['SECRET_KEY'] = 'hjshjhdjah kjshkjdhjs'
    app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{DB_NAME}'
    app.config['MAIL_SERVER'] = 'smtp.gmail.com'
    app.config['MAIL_PORT'] = 587
    app.config['MAIL_USERNAME'] = ''  # Replace with your Gmail email
    app.config['MAIL_PASSWORD'] = ''  # Replace with your Gmail password
    app.config['MAIL_USE_TLS'] = True
    app.config['MAIL_USE_SSL'] = False
    db.init_app(app)
    mail.init_app(app)
    from .views import views
    from .auth import auth

    app.register_blueprint(views, url_prefix='/')
    app.register_blueprint(auth, url_prefix='/')

    from .models import User, Note
    
    with app.app_context():
        db.create_all()
        scheduler.start()

    login_manager = LoginManager()
    login_manager.login_view = 'auth.login'
    login_manager.init_app(app)

    @login_manager.user_loader
    def load_user(id):
        return User.query.get(int(id))

    return app


def create_database(app):
    if not path.exists('website/' + DB_NAME):
        db.create_all(app=app)
        print('Created Database!')

views.py

from flask import Blueprint, render_template, request, flash, jsonify
from flask import current_app
from flask_login import login_required, current_user
from .models import Note
from . import db
import json
from flask import *
from flask_mail import Message
from .__init__ import mail
from . import scheduler
import schedule
import time
from datetime import datetime
from datetime import timedelta
import threading
import logging
from apscheduler.schedulers.background import BackgroundScheduler



views = Blueprint('views', __name__)


@views.route('/', methods=['GET', 'POST'])
@login_required
def home():
    logging.basicConfig(level=logging.DEBUG)
    logging.debug(datetime.now().date())
    with current_app.app_context():
        if request.method == 'POST': 
            note = request.form.get('note')
            scheduled_date = request.form.get('date')
            logging.debug("AAAAA")
            logging.debug(scheduled_date)

            if len(note) < 1:
                flash('Note is too short!', category='error') 
            else:
                new_note = Note(data=note, user_id=current_user.id)
                db.session.add(new_note)
                db.session.commit()
                flash('Note added!', category='success')
            
            if scheduled_date:
                schedule_email(current_user.email, note, scheduled_date, current_app)
        
    return render_template("home.html", user=current_user)

def schedule_email(email, note, scheduled_date, app):
    with app.app_context():
        scheduled_datetime = datetime.strptime(scheduled_date, "%Y-%m-%d")
        scheduled_date_only = scheduled_datetime.date()  # Extract only the date part

        if scheduled_date_only >= datetime.now().date():
            extended_run_date = scheduled_datetime + timedelta(minutes=542) 
            scheduler.add_job(send_scheduled_email, 'date', args=[email, note, app], run_date=extended_run_date)
            flash('Email scheduled!', category='success')
        else:
            flash('Scheduled date must be in the future!', category='error')
def send_scheduled_email(email, body, app):
    msg = Message('Password Change', sender='')
    msg.add_recipient(email)
    logging.debug('Sending scheduled email')
    mail.send(msg)


@views.route('/delete-note', methods=['POST'])
def delete_note():  
    note = json.loads(request.data) # this function expects a JSON from the INDEX.js file 
    noteId = note['noteId']
    note = Note.query.get(noteId)
    if note:
        if note.user_id == current_user.id:
            db.session.delete(note)
            db.session.commit()

    return jsonify({})

app.py

from website import create_app
from flask import Flask

app = create_app()

if __name__ == '__main__':
    app.run(debug=True)
    ```



I have tried to use with app.app_context() in send_scheduled_email(email, body, app) but didn't work
0

There are 0 best solutions below