Email & Templates
AnvilBase sends transactional email for auth flows — magic links, email verification, password reset, team invites, and welcome messages. Email delivery is configured per project via SMTP, and every template is customizable.
Configure SMTP
A deployment can set default SMTP in .env (SMTP_HOST, SMTP_PORT, …), but most
teams set it per project so each app sends from its own domain.
Local development (Mailpit)
Mailpit is the catch-all SMTP service bundled with the AnvilBase local stack. It captures every outbound email so nothing reaches real inboxes. Browse captured mail at http://localhost:8025.
# One command — no flags needed, Mailpit defaults are pre-setanvctl projects smtp set <id>
# Confirm the config was savedanvctl projects smtp show <id>Production provider
anvctl projects smtp set <id> \ --host smtp.sendgrid.net --port 587 \ --from noreply@myapp.com --from-name "My App" \ --user apikey --encryption starttls# Password is prompted interactively (not logged / visible in shell history)Via MCP (AI coding agents)
anvilbase_configure_smtp project_id: <id> host: mailpit # or your production relay port: 1025 from_email: noreply@anvilbase.local from_name: AnvilBase encryption: noneVia REST API
curl -X PUT http://localhost:39001/api/v1/projects/<id>/email/smtp \ -H "Authorization: Bearer $ANVILBASE_TOKEN" -H "Content-Type: application/json" \ -d '{ "host": "smtp.example.com", "port": 587, "username": "postmaster@example.com", "password": "•••••", "from_email": "noreply@example.com", "from_name": "My App", "encryption": "starttls" }'| Field | Notes |
|---|---|
host, port | SMTP server (1025 = Mailpit, 587 = STARTTLS, 465 = TLS) |
username, password | credentials (password is write-only — never returned) |
from_email, from_name | sender identity |
encryption | none (Mailpit/local), starttls (port 587), tls (port 465) |
The password is stored AES-256-GCM-encrypted at rest (key derived from the
deployment’s CONTROL_PLANE_SECRET) and decrypted only at send time. No read
path ever returns it — GET .../smtp omits the field and raw project
settings echoes show "[redacted]". Passwords saved by older versions in
plaintext keep working and are re-encrypted on the next write, or in one pass
via POST /api/v1/admin/encrypt-settings-secrets.
Read it back (without the password):
anvctl projects smtp show <id># orcurl http://localhost:39001/api/v1/projects/<id>/email/smtp \ -H "Authorization: Bearer $ANVILBASE_TOKEN"# → { host, port, username, from_email, from_name, encryption, configured }Send a test email
curl -X POST http://localhost:39001/api/v1/projects/<id>/email/test \ -H "Authorization: Bearer $ANVILBASE_TOKEN" -H "Content-Type: application/json" \ -d '{"to":"you@example.com","template":"welcome"}'Returns { success, message }; 400 if SMTP isn’t configured yet. In local dev,
the email appears at http://localhost:8025 (Mailpit).
Templates
Five template types, each customizable per project:
template_type | Sent when |
|---|---|
magic_link | a user requests passwordless sign-in |
verify_email | a new account needs email confirmation |
reset_password | a user requests a password reset |
invite | a teammate is invited to the project |
welcome | automatically, after a new user signs up (renders {{user_name}}) |
Template variables
Use these placeholders in subject / body_html / body_text:
| Variable | Value |
|---|---|
{{user_name}} | recipient’s name |
{{action_url}} | the magic link / verify / reset / accept URL |
{{project_name}} | the project’s name |
{{expires_in}} | how long the link is valid |
Create or update a template
curl -X PUT http://localhost:39001/api/v1/projects/<id>/email/templates/magic_link \ -H "Authorization: Bearer $ANVILBASE_TOKEN" -H "Content-Type: application/json" \ -d '{ "subject": "Your sign-in link for {{project_name}}", "body_html": "<p>Hi {{user_name}},</p><p>Click to sign in: <a href=\"{{action_url}}\">Sign in</a></p><p>Expires in {{expires_in}}.</p>", "body_text": "Hi {{user_name}}, sign in: {{action_url}} (expires in {{expires_in}})" }'List your templates / see the defaults
# Your custom templatescurl http://localhost:39001/api/v1/projects/<id>/email/templates -H "Authorization: Bearer $ANVILBASE_TOKEN"
# The built-in defaults (subjects + HTML) for all typescurl http://localhost:39001/api/v1/projects/email/templates/defaults -H "Authorization: Bearer $ANVILBASE_TOKEN"Delete (revert to default)
curl -X DELETE http://localhost:39001/api/v1/projects/<id>/email/templates/magic_link \ -H "Authorization: Bearer $ANVILBASE_TOKEN"Deleting a custom template falls back to AnvilBase’s built-in default for that type.
In the console
Project → Email tab provides a form for SMTP config and a side-by-side editor (with live preview) for each template. The Send test button uses the project’s SMTP.
Deliverability tips
- Configure SPF, DKIM, and DMARC for your sending domain.
- Use a reputable relay (SES, Postmark, Mailgun, Resend) rather than a raw box.
- Keep
from_emailon a domain you control and that matches your DKIM signing. - Test the full magic-link / reset flows end-to-end after changing SMTP — a silent delivery failure looks identical to a broken auth flow to your users.
Next: Realtime → Overview.