Flask-Mail

A lightweight Flask extension that adds SMTP email sending to your application with a simple Message API.

Library
PyPI
v0.10.0
642stars
BSD 3-Clause License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
53/100Fair
Development Activity28
Maintenance24
Community80
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
75/100Good
Architecture72
Code Quality78
Innovation68
Learning Curve82

Flask-Mail is a small extension for Flask that wraps Python’s built-in smtplib and email modules into a Flask-friendly API for composing and sending SMTP mail. It handles the fiddly parts of email — multipart plain-text/HTML bodies, file attachments, header sanitization for unicode subjects and addresses, and connection pooling for bulk sends — so application code only has to build a Message and call mail.send().

Maintained as part of the Pallets Community Ecosystem (the group that maintains Flask, Jinja, and Click), it has been a stable choice for adding transactional email to Flask apps since 2010 and still ships active BSD-3-Clause releases with full type annotations.

What You Get

  • A Mail Flask extension initialized via init_app(), following the standard Flask extension pattern
  • A Message class supporting plain-text bodies, HTML alternatives, CC/BCC, reply-to, custom headers, and ESMTP mail/rcpt options
  • File attachment support via an Attachment class with automatic content-type detection from filename
  • A Connection context manager that batches multiple sends over one SMTP connection and reconnects after MAIL_MAX_EMAILS
  • A record_messages() context manager and MAIL_SUPPRESS_SEND testing flag so tests can assert on sent messages without hitting a real SMTP server
  • A blinker-based email_dispatched signal fired on every send (including suppressed test sends) for hooking in logging or auditing

Common Use Cases

  • Sending account-related transactional email (password resets, signup confirmations, notifications) from a Flask backend
  • Sending HTML + plain-text multipart emails with inline attachments such as invoices or reports
  • Batching bulk notification emails over a single pooled SMTP connection instead of reconnecting per message
  • Asserting on outgoing email content in test suites via record_messages() without configuring a real mail server

Under The Hood

Architecture Flask-Mail is a single-module extension (src/flask_mail/__init__.py) with four cooperating pieces: Mail (the Flask extension, holding an internal _Mail state object registered into app.extensions["mail"]), Message (the email being composed, exposing body/html/alts and building a MIME tree lazily in _message()), Connection (a context manager wrapping an smtplib.SMTP/SMTP_SSL socket, reused across multiple send() calls and reconnected every MAIL_MAX_EMAILS), and a blinker.Namespace signal (email_dispatched) fired after every send, real or suppressed, so tests and logging hooks can observe outgoing mail without touching the network. Mail.send() opens a Connection, calls message.send(connection), which delegates to Connection.send() to build the MIME payload and call smtplib’s sendmail. Tech Stack Pure Python with two runtime dependencies — flask (for current_app and the extension registration pattern) and blinker (for the dispatch signal) — and no other third-party code; everything else is standard library (smtplib, email.mime, mimetypes). Packaged with flit_core via pyproject.toml, targets Python 3.9+, and is fully typed (ships py.typed, checked with strict mypy and pyright). Code Quality The tests/ directory holds 812 lines across five files covering message construction, header sanitization edge cases (unicode subjects, IDN addresses, CRLF injection in has_bad_headers), connection pooling/reconnect behavior, and Flask app initialization, run under pytest with filterwarnings=["error"] so any unexpected warning fails CI; ruff (bugbear, pyflakes, isort, pyupgrade) and pre-commit enforce style, and tox runs the matrix across Python 3.9–3.12 plus docs and typing environments. API Design The public surface is deliberately small — Mail(app), Message(...), and mail.send(msg) — following the standard Flask extension convention (init_app, app.extensions), so anyone familiar with other Flask extensions can pick it up immediately; sensible config defaults (e.g. MAIL_SERVER defaults to 127.0.0.1, MAIL_PORT to 25) mean a minimal setup needs only a handful of config keys, and the deprecated is_bad_headers/__version__ APIs emit clear DeprecationWarnings pointing at their replacements.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search