python
49 lines · 8 steps
Sending welcome emails off the request thread in Flask
A signup route creates a user and dispatches a welcome email on a background thread so the response returns immediately.
Explained by
highlit
1import smtplib
2from email.message import EmailMessage
3from threading import Thread
4
5from flask import Blueprint, current_app, jsonify, request
6
7users = Blueprint("users", __name__)
8
9
10def _send_email(app, recipient, name):
11 with app.app_context():
12 msg = EmailMessage()
13 msg["Subject"] = "Welcome aboard!"
14 msg["From"] = current_app.config["MAIL_FROM"]
15 msg["To"] = recipient
16 msg.set_content(
17 f"Hi {name},\n\nThanks for signing up. We're glad to have you."
18 )
19 try:
20 with smtplib.SMTP(
21 current_app.config["SMTP_HOST"],
22 current_app.config["SMTP_PORT"],
23 timeout=10,
24 ) as server:
25 server.starttls()
26 server.login(
27 current_app.config["SMTP_USER"],
28 current_app.config["SMTP_PASSWORD"],
29 )
30 server.send_message(msg)
31 except Exception:
32 current_app.logger.exception("Failed to send welcome email to %s", recipient)
33
34
35def send_welcome_email_async(recipient, name):
36 app = current_app._get_current_object()
37 Thread(target=_send_email, args=(app, recipient, name), daemon=True).start()
38
39
40@users.route("/signup", methods=["POST"])
41def signup():
42 data = request.get_json(force=True)
43 email = data["email"]
44 name = data.get("name", "there")
45
46 user = User.create(email=email, name=name)
47 send_welcome_email_async(user.email, user.name)
48
49 return jsonify(id=user.id, email=user.email), 201
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Offloading slow I/O like SMTP to a background thread keeps HTTP responses fast.
- 2Flask's request-bound context doesn't exist in new threads, so you must push an app context manually.
- 3Capture the real app object before spawning a thread, since context-local proxies won't resolve outside the request.
Related explainers
python
import random import click from faker import Faker
Building a Flask seed command with Click
cli
database seeding
orm
Intermediate
7 steps
python
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin from django.shortcuts import get_object_or_404 from django.views.generic import DetailView
Team membership access control in Django
access-control
mixins
class-based-views
Intermediate
7 steps
python
import uuid from pathlib import Path from fastapi import APIRouter, File, Form, HTTPException, UploadFile
Handling multipart file uploads in FastAPI
file-upload
validation
multipart-form
Intermediate
6 steps
python
from copy import deepcopy from typing import Any, Mapping
How a recursive deep merge works in Python
recursion
immutability
dictionaries
Intermediate
6 steps
python
from difflib import SequenceMatcher from bisect import bisect_left, bisect_right
Building a fuzzy autocomplete matcher
fuzzy-matching
binary-search
ranking
Intermediate
9 steps
python
import secrets from datetime import datetime, timedelta, timezone from fastapi import APIRouter, Cookie, Depends, HTTPException, Response, status
Cookie session auth in FastAPI
session-authentication
cookies
dependency-injection
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/sending-welcome-emails-off-the-request-thread-in-flask-explained-python-2554/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.