DocsSelf HostingEmail Delivery
Back to Self-Hosting

Email Delivery & Team Invites

How Hyperswitch sends auth emails (team invites, signup verification, magic links, password reset), how to wire any SMTP provider, and how to invite teammates — from zero to working in production.

What Email Enables

Without an email provider, the Control Center still works — but team onboarding is manual: an admin invites a teammate and the router generates a password that gets downloaded as a file to share out of band. Configuring email switches the flow to fully self-service:

  • Team invites — admin adds a teammate's email + role, the router emails an invite link they click to set their password.
  • Signup verification & magic links — email-based login/verification.
  • Password reset — users reset their own passwords.

Pick Any SMTP Provider

Hyperswitch only needs standard SMTP credentials — so any provider works. Same config shape, different values:

ProviderSMTP hostPortusernamepassword
Resendsmtp.resend.com587your Resend API keyyour Resend API key
Amazon SESemail-smtp.<region>.amazonaws.com587SES SMTP usernameSES SMTP password
Postmarksmtp.postmarkapp.com587Postmark SMTP tokenany value
Brevosmtp-relay.brevo.com587Brevo SMTP loginBrevo SMTP key
SendGridsmtp.sendgrid.net587apikeySendGrid API key
Mailchimp (Mandrill)smtp.mandrillapp.com587your Mandrill SMTP usernameyour Mandrill API key
Mailgunsmtp.mailgun.org587postmaster@yourdomain.comMailgun SMTP password

Every provider requires verifying a domain you own (DNS records: SPF, DKIM, optionally DMARC) before it will send. This is done in the provider's dashboard — the sender address you configure below must sit on that verified domain.

Configure It in One Place

Edit the root .env — the Docker Compose file already maps these into the Hyperswitch router. For local development, start the bundled MailHog (catches every email in a web UI at http://localhost:8025):

root .env — email section
# Dev (MailHog): catches emails locally, no provider needed
EMAIL_ACTIVE_CLIENT=SMTP
EMAIL_SENDER_EMAIL=no-reply@yourdomain.com
EMAIL_SMTP_HOST=mailhog
EMAIL_SMTP_PORT=1025
EMAIL_SMTP_CONNECTION=plaintext
EMAIL_SMTP_TIMEOUT=10
# MailHog accepts ANY credentials, but they must NOT be empty
# (an empty username/password crashes the router at startup)
EMAIL_SMTP_USERNAME=mailhog
EMAIL_SMTP_PASSWORD=mailhog

# PRODUCTION (Resend example) — uncomment & fill:
# EMAIL_SMTP_HOST=smtp.resend.com
# EMAIL_SMTP_PORT=587
# EMAIL_SMTP_CONNECTION=start_tls
# EMAIL_SMTP_USERNAME=re_xxxxxxxxxxxxxxxxxx
# EMAIL_SMTP_PASSWORD=re_xxxxxxxxxxxxxxxxxx

# Public URLs (MUST be public in production, not localhost)
HYPERSWITCH_DASHBOARD_URL=https://dashboard.yourdomain.com
HYPERSWITCH_PUBLIC_API_URL=https://api.yourdomain.com

# Turn on email-based team invites in the Control Center UI
HYPER_EMAIL_ENABLED=true

Case-sensitive: EMAIL_SMTP_CONNECTION must be the literal plaintext (dev/MailHog) or start_tls (production) — not "starttls".

Required: EMAIL_SMTP_USERNAME and EMAIL_SMTP_PASSWORD must be non-empty. Even MailHog (which ignores credentials) will crash the router if they are blank — use any placeholder value like mailhog / mailhog.

⚠️ The “Invalid Link or session expired” gotchas:

  • Empty database. The email-enabled router image needs ~493 tables. If you never ran make migrate-db, the DB has zero tables and every login/signup fails with this exact error. Run the migration once and it stays fixed.
  • Wrong image. The juspaydotin/hyperswitch-router:standalone image has the email feature compiled out (email routes 404; no email is ever sent). Use the full build, e.g. juspaydotin/hyperswitch-router:v1.125.0.
  • Localhost link. If HYPERSWITCH_DASHBOARD_URL is left as localhost, every email link points at localhost — unreachable from any inbox. Set it to the public URL in production.

Apply the Change

terminal
# 1. Start the database first (the migration script needs core-postgres up):
docker compose up -d postgres

# 2. First run only: apply the Hyperswitch DB migrations.
# The email-enabled router image needs ~493 tables (users, merchant_account, ...).
# Without them every login fails with "Invalid Link or session expired".
./scripts/migrate-hyperswitch-db.sh   # or: make migrate-db (if make is installed)

# 3. Dev: start MailHog + the full stack
docker compose --profile core --profile dev up -d

# Production: no MailHog — just restart the router & control center
docker compose up -d --force-recreate hyperswitch hyperswitch-control-center

# See MailHog's caught emails at http://localhost:8025

How to Invite a Teammate

  1. Open the Control Center at http://localhost:9000 and sign in as the org admin (the first account created).
  2. Go to Settings → Team → Invite New Users.
  3. Enter the teammate's email and assign a role (Organization Admin, Merchant Developer, View-Only, or a custom role).
  4. Submit. With email configured, the teammate receives an invite email with a link. They click it, set a password, and are in.
  5. Without email configured, the router instead lets you download the credentials file (email + generated password) to share manually — same outcome, less self-service.

Team Login Options

  • Password — email + password (set during invite acceptance).
  • Magic Link — email a one-time login link (requires email config).
  • SSO / OIDC — Google/GitHub/Okta via the router's [oidc] config.
  • 2FA (TOTP) — authenticator-app codes, optional per deployment (force_two_factor_auth).

Full Email Env Reference

Env varMaps toPurpose
EMAIL_ACTIVE_CLIENTROUTER__EMAIL__ACTIVE_EMAIL_CLIENTSMTP or SES
EMAIL_SENDER_EMAILROUTER__EMAIL__SENDER_EMAILFrom: address (must be on the verified domain)
EMAIL_SMTP_HOSTROUTER__EMAIL__SMTP__HOSTProvider SMTP host
EMAIL_SMTP_PORTROUTER__EMAIL__SMTP__PORTUsually 587 (start_tls) or 1025 (MailHog)
EMAIL_SMTP_CONNECTIONROUTER__EMAIL__SMTP__CONNECTIONplaintext (dev) or start_tls (production)
EMAIL_SMTP_TIMEOUTROUTER__EMAIL__SMTP__TIMEOUTSeconds before timeout (default 10)
EMAIL_SMTP_USERNAMEROUTER__EMAIL__SMTP__USERNAMEProvider SMTP username/API key
EMAIL_SMTP_PASSWORDROUTER__EMAIL__SMTP__PASSWORDProvider SMTP password/API key
HYPERSWITCH_DASHBOARD_URLROUTER__USER__BASE_URLPublic dashboard URL baked into email links
HYPERSWITCH_PUBLIC_API_URLdefault__config__api_url / sdk_url (Control Center)Public router URL the Control Center calls from the browser
HYPER_EMAIL_ENABLEDdefault__features__email (Control Center)true = email-based invites in the UI
Next: Third-Party Tools →