Prolifto
Developer guide

Email

Send transactional email through SMTP and test it locally with Mailpit.

Transactional email is sent with Nodemailer through SMTP. The email service lives in @prolifto/infrastructure.

Local development

Start Mailpit:

pnpm mail:up

Mailpit accepts any username and password and captures every message. Use the SMTP_* values from the env examples. Reset captured messages with:

pnpm mail:reset

What email is sent

EmailTrigger
Sign-in / verification OTPAdmin or storefront auth
Organization invitationA member is invited to a store
Order confirmationAn order is created, or an admin resends it
Account deletion linkA user requests account deletion

There is no marketing email or campaign system in the current codebase.

SMTP configuration

SMTP_FROM="Prolifto <dev@example.com>"
SMTP_HOST="localhost"
SMTP_PORT="2525"
SMTP_USER="dev@example.com"
SMTP_PASS="mailpit"

Port 465 enables implicit TLS; other ports use STARTTLS when the server supports it. The sender uses a 5-second connection timeout and a 10-second socket timeout and throws on delivery failure so Inngest can retry.

In production, use a real SMTP provider and a sender address that the provider has verified. Never use a Vercel domain as SMTP_FROM. Do not send from example.com in production.

Adding an email

  1. Create a template builder in packages/infrastructure/src/email.
  2. Reuse email-layout.ts for consistent branding.
  3. Escape user-supplied values with escape-html.ts.
  4. Send it from a service or an Inngest function.
  5. Add a test for the rendered subject and key content.
  6. Test locally in Mailpit before merging.

Debugging

  • No message arrives: check Mailpit is running and the SMTP_* values match.
  • Authentication fails in production: verify the SMTP username, password, and port, and confirm the provider allows the sender.
  • Messages are retried: the send function throws on failure; check the Inngest run for the error.
  • Wrong links: check NEXT_PUBLIC_APP_URL, NEXT_PUBLIC_FRONTEND_URL, and the storefront domain configuration.

On this page