Skip to content
Feeblo Docs
Esc
navigateopen⌘Jpreview
On this page

Email

How Feeblo sends mail. The SMTP transport variables, the Amazon SES feedback webhook, and the outbox controls.

Feeblo sends every kind of mail through one mailer: verification and password reset links, onboarding and user-feedback digests, weekly summaries, and notifications. The server records each message in an outbox table and a worker inside the server process delivers it, so a failed send retries instead of vanishing.

Sign-up blocks on email by default: new accounts must click a verification link (AUTH_EMAIL_VERIFICATION_REQUIRED defaults to true). Get SMTP working before you open registrations, or nobody gets in.

Transports

The repo documents three transport names in .env.example:

Value Meaning
smtp-auth default. SMTP with username and password
smtp-api documented option, no implementation in this source
resend documented option, no implementation in this source

SMTP variables

Variable Default Notes
SMTP_HOST 127.0.0.1 Mail server host
SMTP_PORT 2500 The dev stack uses 1025 (Mailpit)
SMTP_USERNAME unset Auth is only attempted when this is set
SMTP_PASSWORD unset Paired with SMTP_USERNAME
SMTP_SECURE false true forces TLS on the connection
SMTP_UNSAFE_IGNORE_TLS false true skips TLS even when the server offers STARTTLS
SMTP_SERVICE unset Well-known nodemailer service name (for example gmail)
SMTP_FROM_ADDRESS hello@feeblo.com The from address for all mail
SMTP_FROM_NAME unset Listed in .env.example, but no code reads it; setting it does nothing
SMTP_PERSONAL_FROM_ADDRESS unset Sender for onboarding and user-feedback mail; falls back to SMTP_FROM_ADDRESS

TLS behavior follows nodemailer semantics. With SMTP_SECURE=true, the connection upgrades to TLS up front. With SMTP_SECURE=false (default) the client uses STARTTLS when the server offers it, and SMTP_UNSAFE_IGNORE_TLS=true disables even that. Leave the ignore flag alone unless your relay serves plaintext only.

The from-address trio deserves attention before you launch:

  • SMTP_FROM_ADDRESS appears on every message unless a template overrides it.
  • SMTP_PERSONAL_FROM_ADDRESS gives personal lifecycle mail (onboarding, user feedback) its own sender. Unset, it falls back to SMTP_FROM_ADDRESS.
  • Skip SMTP_FROM_NAME: it sits in .env.example as “required”, but nothing in the codebase reads it.

Outbox controls

Delivery pauses and cost guards are environment-driven so an operator can react without redeploying. All five variables are optional and live in packages/domain/src/email-outbox/:

Variable Default Meaning
EMAIL_OUTBOX_GLOBAL_DELIVERY_PAUSED false true stops all outbound delivery immediately
EMAIL_OUTBOX_MAX_CONCURRENT_SENDS 10 Worker concurrency; clamps to at least 1
EMAIL_OUTBOX_MONTHLY_SEND_LIMIT 100000 Monthly send budget; clamps to at least 1
EMAIL_OUTBOX_ESTIMATED_SEND_COST_MICROS 100 Assumed cost per send in microdollars for cost tracking
EMAIL_OUTBOX_PAUSED_WORKSPACE_IDS empty Comma-separated workspace IDs whose mail is paused

Set EMAIL_OUTBOX_GLOBAL_DELIVERY_PAUSED=true while you migrate providers or fix a bounced-sender problem. Messages keep queuing in the outbox, and delivery resumes when you flip the flag back. EMAIL_OUTBOX_PAUSED_WORKSPACE_IDS pauses a single tenant the same way; the server splits the comma-separated list and trims whitespace.

Amazon SES feedback webhook

Feeblo can ingest Amazon SES delivery events: deliveries, bounces, and complaints. Two variables switch it on:

  • EMAIL_PROVIDER_WEBHOOK_TOKEN activates the webhook at POST /email-provider/ses/:token. Generate it with openssl rand -hex 32. The token must not be derivable from AUTH_ENCRYPTION_KEY, so a dedicated random value is required.
  • EMAIL_PROVIDER_SNS_TOPIC_ARN filters incoming messages by their signed SNS topic. Set it whenever the token is set: the webhook rejects messages whose TopicArn does not match, and without it the source is unverifiable, so requests get rejected anyway.

Subscribe your SNS topic to:

https://<API_URL>/email-provider/ses/<EMAIL_PROVIDER_WEBHOOK_TOKEN>

Leave both variables unset and the route stays inert (404). SNS sends its notifications over a publicly reachable HTTPS URL, so point the topic subscription at the server’s public API_URL.

Next steps

Was this page helpful?