Post

Bootcamp Tutorial 5: Flask, Celery, Redis, and SMTP Integration


In this tutorial, we integrate Flask, Celery, Redis, Flask-Caching, and SMTP to build an app that supports:

  • Sending emails via SMTP
  • Caching API responses
  • Clearing cache dynamically
  • Background task queuing
  • Scheduled tasks with Celery Beat

Prerequisites

Install required dependencies:

1
pip install Flask Flask-RESTful Celery redis Flask-Mail Flask-Caching python-dotenv

Ensure Redis is installed and running:

1
2
3
sudo apt update
sudo apt install redis-server
sudo systemctl start redis

Setup: Flask Application

Create a file main.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import os
from flask import Flask, request
from flask_restful import Api, Resource
from flask_mail import Mail, Message
from flask_caching import Cache
from celery import Celery
from dotenv import load_dotenv
from celery.schedules import crontab

# Load .env
load_dotenv()

app = Flask(__name__)
api = Api(app)

# ============================
# Flask-Mail Configuration
# ============================
app.config['MAIL_SERVER'] = 'smtp.gmail.com'
app.config['MAIL_PORT'] = 587
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USERNAME'] = os.getenv('MAIL_USER')
app.config['MAIL_PASSWORD'] = os.getenv('MAIL_PASS')
app.config['MAIL_DEFAULT_SENDER'] = os.getenv('MAIL_USER')
mail = Mail(app)

# ============================
# Flask-Caching with Redis
# ============================
app.config['CACHE_TYPE'] = 'RedisCache'
app.config['CACHE_REDIS_HOST'] = 'localhost'
app.config['CACHE_REDIS_PORT'] = 6379
app.config['CACHE_REDIS_DB'] = 1
app.config['CACHE_REDIS_URL'] = 'redis://localhost:6379/1'
app.config['CACHE_DEFAULT_TIMEOUT'] = 60
cache = Cache(app)

# ============================
# Celery Configuration
# ============================
app.config['broker_url'] = os.getenv('BROKER_URL', 'redis://localhost:6379/0')
app.config['result_backend'] = os.getenv('RESULT_BACKEND', 'redis://localhost:6379/0')

celery = Celery(app.name, broker=app.config['broker_url'], backend=app.config['result_backend'])
celery.conf.broker_connection_retry_on_startup = True

# ============================
# Celery Context Setup
# ============================
def init_celery(flask_app):
    celery_app = Celery(
        flask_app.import_name,
        broker=flask_app.config['broker_url'],
        backend=flask_app.config['result_backend']
    )
    celery_app.conf.update(flask_app.config)

    class ContextTask(celery_app.Task):
        def __call__(self, *args, **kwargs):
            with flask_app.app_context():
                return super().__call__(*args, **kwargs)

    celery_app.Task = ContextTask
    return celery_app

celery = init_celery(app)

1. Send Emails with SMTP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class SendEmail(Resource):
    def get(self):
        email = request.args.get('email')
        if not email:
            return {'message': 'Error: No email provided'}, 400

        msg = Message(
            subject="Test Email from Flask",
            recipients=[email],
            body="This is a test email sent via Flask and SMTP."
        )

        try:
            mail.send(msg)
            return {'message': f'Email sent to {email}!'}, 200
        except Exception as e:
            return {'message': f"Error: {str(e)}"}, 500

api.add_resource(SendEmail, '/send-email')

Test:

1
curl "http://localhost:5000/send-email?email=you@example.com"

2. Caching with Flask-Caching

1
2
3
4
5
6
class CacheDemo(Resource):
    @cache.cached()
    def get(self):
        return {'data': 'This is a cached response!'}, 200

api.add_resource(CacheDemo, '/cache')

Clear Cache

1
2
3
4
5
6
class DeleteCache(Resource):
    def post(self):
        cache.clear()
        return {'message': 'Cache cleared successfully!'}, 200

api.add_resource(DeleteCache, '/delete-cache')

Test:

1
2
curl http://localhost:5000/cache
curl -X POST http://localhost:5000/delete-cache

3. Background Task with Celery

1
2
3
4
5
6
7
8
9
10
@celery.task(name="tasks.background_task")
def background_task():
    return 'Background task completed'

class QueuedTask(Resource):
    def get(self):
        task = background_task.apply_async()
        return {'task_id': task.id}, 202

api.add_resource(QueuedTask, '/queued-task')

4. Schedule Daily Task with Celery Beat

1
2
3
4
5
6
7
8
9
10
11
12
celery.conf.timezone = 'Asia/Kolkata'
celery.conf.beat_schedule = {
    'daily-reminder': {
        'task': 'tasks.send_reminders',
        'schedule': crontab(hour=7, minute=0),
    },
}

@celery.task(name="tasks.send_reminders")
def send_reminders():
    print("Reminder sent at 7:00 AM IST!")
    return "Reminder triggered"

.env File Example

1
2
3
4
MAIL_USER=your_email@gmail.com
MAIL_PASS=your_email_password
BROKER_URL=redis://localhost:6379/0
RESULT_BACKEND=redis://localhost:6379/0

Running the App

1
2
3
4
5
6
7
8
# 1. Run Flask
python3 main.py

# 2. Start Celery Worker
celery -A main.celery worker --loglevel=info

# 3. Start Celery Beat
celery -A main.celery beat --loglevel=info

Test Endpoints

  • Send Email: GET /send-email?email=you@example.com
  • Cache Demo: GET /cache
  • Clear Cache: POST /delete-cache
  • Queue Task: GET /queued-task
  • Daily Reminder: Check logs after 7:00 AM IST

That’s it!

You’ve successfully integrated Flask with Flask-Caching, Celery, Redis, and SMTP. Happy coding!

This post is licensed under CC BY 4.0 by the author.