Skip to content

Email

FastAuth sends five kinds of email: welcome, verification, password reset, email-change confirmation, and magic-link login. Email is opt-in: if email_transport is None (the default), every send_* is a silent no-op and the email-based flows still function — they just don't deliver anything. This is useful for local development.

Configure a transport

from fastauth.email_transports.console import ConsoleTransport  # dev
from fastauth.email_transports.smtp import SMTPTransport         # prod
from fastauth.email_transports.webhook import WebhookTransport   # custom provider

# Console: prints to stdout. No deps.
config = FastAuthConfig(..., email_transport=ConsoleTransport())

# SMTP: requires [email] extra
config = FastAuthConfig(..., email_transport=SMTPTransport(
    host="smtp.example.com", port=587,
    username="user", password="pass",
    from_email="noreply@example.com",
    use_tls=True,
))

# Webhook: posts JSON {to, subject, body_html, body_text?} to a URL. Requires [oauth] (httpx).
config = FastAuthConfig(..., email_transport=WebhookTransport(
    url="https://your-email-provider.example/send",
    headers={"Authorization": "Bearer ..."},
))

Implement EmailTransport.send(to, subject, body_html, body_text=None) for anything else.

Templates

Built-in Jinja2 templates ship in fastauth/templates/. Override any of them by pointing email_template_dir at a directory; FastAuth uses a ChoiceLoader, so only the files you place there override the built-ins — everything else falls back automatically.

from pathlib import Path
config = FastAuthConfig(..., email_template_dir=Path("my_templates/"))
File Sent when Variables
welcome.jinja2 when you call EmailDispatcher.send_welcome_email name
verification.jinja2 POST /auth/request-verify-email name, url, expires_in_minutes
password_reset.jinja2 POST /auth/forgot-password name, url, expires_in_minutes
email_change.jinja2 POST /auth/change-email name, new_email, url, expires_in_minutes
magic_link_login.jinja2 POST /auth/magic-links/login name, url

name resolves to user["name"] or user["email"] when the name is missing.

FastAuth builds the links using base_url:

Flow URL pattern
Email verification {base_url}/auth/verify-email?token=...
Password reset {base_url}/auth/reset-password?token=...
Email change {base_url}/auth/account/confirm-email-change?token=...
Magic link {base_url}/auth/magic-links/callback?token=...

The token sent in the email is the raw token. The database stores its SHA-256 hash. Tokens are one-time; consumption is atomic on TokenAdapter.consume_token.

Common mistakes

  • Setting email_transport without the email extraSMTPTransport raises MissingDependencyError: 'aiosmtplib' is required... Install: pip install sreekarnv-fastauth[email] when first used.
  • Expecting a verification email at registration — it is not sent. The user must call POST /auth/request-verify-email. See Email verification.
  • base_url left as http://localhost:8000 in production — the link in the email will be unusable (or rejected by Secure cookies when clicked).