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