Feeblo sends transactional email over SMTP using nodemailer. Configure the SMTP_* variables; dev defaults point at Mailpit.
Transactional email (verification codes, etc.) is sent through a single nodemailer SMTP transport built from the SMTP_* environment variables. There is no separate mail driver selection — one transport, configured by env.
This page is based on packages/transactional/src/mailer.ts, packages/transactional/src/config.ts, and .env.example in .reference/.
How it sends
packages/transactional/src/mailer.ts builds a nodemailer transport with these knobs:
- Renders an email's React template to HTML via
@react-email/render, derives a plain-text version withtoPlainText, and sends both. - Sets
fromto the configuredSMTP_FROM_ADDRESSunless the caller overrides it per-message (with an optionalreplyTo).
Environment variables
These are the variables MailerConfig (packages/transactional/src/config.ts) actually reads at runtime, with the in-code defaults:
Prop
Type
SMTP_SECURE and SMTP_UNSAFE_IGNORE_TLS are parsed as the literal strings "true" / "false"; anything else fails to start with a config error (Expected … to be "true" or "false"). SMTP_PORT must parse as an integer.
What .env.example declares vs what the code reads
.env.example ships two more variables the comments describe but the code does not consume in this snapshot:
SMTP_FROM_NAME="Feeblo"— declared, butMailerConfigonly builds a plain address forfrom. The "Feeblo" name is not currently attached to theFromheader.SMTP_TRANSPORT(commented options:smtp-auth/smtp-api/resend) — declared in the example as a transport selector, butMailerConfigbuilds a single nodemailer SMTP transport and never readsSMTP_TRANSPORT. Resend / SMTP-API variants are not wired up here.
Don't rely on the commented transport options
If you set SMTP_TRANSPORT=resend expecting the Resend API to be used, nothing changes — Feeblo
will still build an SMTP transport from SMTP_HOST/SMTP_PORT/SMTP_*. Configure your Resend
account over SMTP (Resend exposes an SMTP endpoint), or wait for the documented selection to land
in code. Setting SMTP_FROM_NAME likewise has no effect on the From header today.
The fields the code does read all have sensible defaults, so for purely local development you can leave most of them unset and point at the dev Mailpit container.
Local development with Mailpit
The dev compose runs Mailpit (axllent/mailpit). Mailpit accepts SMTP on 1025 and shows a web UI on http://localhost:8025 where you can read every message Feeblo sends. The example values match:
SMTP_HOST="127.0.0.1"
SMTP_PORT=1025
SMTP_FROM_ADDRESS="noreply@feeblo.com"
# No auth, no TLS — leave SMTP_USERNAME / SMTP_PASSWORD / SMTP_SECURE unsetThe dev port differs from the code default
MailerConfig defaults SMTP_PORT to 2500 when SMTP_PORT is unset, but the example sets it
to 1025 to match Mailpit. If you remove that line you'll send to port 2500 on your SMTP host,
which is almost certainly not what you want.
Production providers
For a hosted SMTP provider, set the auth credentials and turn TLS on:
SMTP_HOST="smtp.your-provider.com"
SMTP_PORT=465
SMTP_SECURE="true"
SMTP_USERNAME="apikey"
SMTP_PASSWORD="your-smtp-password"
SMTP_FROM_ADDRESS="noreply@feeblo.example.com"SMTP_SECURE="true" is right for port 465 (implicit TLS). For STARTTLS-on-587, leave SMTP_SECURE false and don't set SMTP_UNSAFE_IGNORE_TLS — nodemailer will negotiate STARTTLS when the server advertises it. Set SMTP_UNSAFE_IGNORE_TLS="true" only in deliberately insecure tracer setups.
Alternatively, set SMTP_SERVICE to a nodemailer service name (e.g. "gmail", "outlook") and you can omit SMTP_HOST/SMTP_PORT:
SMTP_SERVICE="gmail"
SMTP_USERNAME="you@gmail.com"
SMTP_PASSWORD="app-password"
SMTP_FROM_ADDRESS="you@gmail.com"Templates
Email bodies are React Email templates under packages/transactional/src/templates/. They're rendered server-side with @react-email/render; the package also ships an email dev script (pnpm --filter @feeblo/transactional email dev) that runs the React Email preview server on port 3005 for iterating on templates without sending real mail.
Media storage
Feeblo uploads profile images, organization logos, and editor media to an S3-compatible bucket. Configure it with MEDIA_UPLOAD_* and optional MEDIA_PUBLIC_BASE_URL.
Development setup
Get the Feeblo monorepo running locally — prerequisites, local infra containers, migrations, seed data, and the dev servers.