DEV Community

Qasim Muhammad
Qasim Muhammad

Posted on • Originally published at developer.nylas.com

Send Supabase Auth Emails From Your Own Mailbox

Supabase's built-in SMTP server delivers 30 auth emails per hour, and only to addresses on your project's team; a production app needs to send confirmations, magic links, and password resets to anyone, at signup speed. That mismatch is by design — the default exists so Auth works out of the box in development, and Supabase's docs point you at custom SMTP the moment you have real users.

Most people plug in a one-way transactional sender and move on. The alternative worth considering: a mailbox your application owns end to end, where outgoing auth mail and incoming replies live at the same address. That's what a Nylas Agent Account gives you — a hosted, API-driven mailbox (the feature is in beta) that happens to speak plain SMTP.

Step one: a mailbox with an app password

Supabase authenticates over SMTP with an app_password set on the grant — your API key never goes near the Supabase dashboard. Create the account with the password in place:

curl --request POST \
  --url "https://api.us.nylas.com/v3/connect/custom" \
  --header "Authorization: Bearer $NYLAS_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "provider": "nylas",
    "settings": {
      "email": "noreply@notifications.yourcompany.com",
      "app_password": "MySecureP4ssword!2024"
    }
  }'
Enter fullscreen mode Exit fullscreen mode

The Nylas CLI equivalent is one line, if you prefer the terminal:

nylas agent account create noreply@notifications.yourcompany.com \
  --app-password "MySecureP4ssword!2024"
Enter fullscreen mode Exit fullscreen mode

Keep the grant_id from the response and the password itself — what's stored server-side is a bcrypt hash, so the password can be reset but never retrieved. The rules: 18–40 characters, mixed case, at least one digit, printable ASCII. Full reference in mail client access.

Prerequisite either way: a registered domain. Trial *.nylas.email subdomains need no DNS setup; production domains need MX and TXT records, covered in the provisioning docs.

Step two: the Supabase side

Dashboard path: project → AuthenticationEmailsSMTP Settings tab → toggle Enable Custom SMTP on. Then map the fields:

Supabase field Value
Sender email The mailbox address
Sender name What recipients see (e.g., Acme Notifications)
Host mail.us.nylas.email (US) or mail.eu.nylas.email (EU)
Port 465
Username Same as Sender email
Password The app_password

Port 465 means implicit TLS — the connection starts encrypted, no STARTTLS negotiation. If your network blocks 465, port 587 works on the same host with STARTTLS; both feed the same outbound pipeline. One hard rule: Sender email must equal Username, because SMTP submissions where MAIL FROM doesn't match the authenticated account get rejected.

Self-hosting Supabase? Skip the dashboard and set the matching GOTRUE_SMTP_* environment variables on the Auth container.

Supabase verifies the connection when you save, so a wrong host or password fails loudly right there rather than silently at the first signup.

What actually changed: before and after

Supabase default SMTP Agent Account as custom SMTP
Rate limit 30 emails per hour 200 messages per account per day (free plan)
Recipients Project team members only Anyone
Sender address Supabase's Your own domain (or a trial *.nylas.email subdomain)
Replies Nowhere to go Land in the mailbox, fire message.created
Intended use Development Production

The recipient restriction on the default server surprises people more than the rate limit does — it's why "signups work for me but not for beta users" is such a common first bug report.

Step three: prove it end to end

Trigger a password reset or magic link — the dashboard's Auth UI has a test-email action, or fire one from your app. Two places to confirm: the recipient inbox, and the mailbox's own Sent folder:

curl --request GET \
  --url "https://api.us.nylas.com/v3/grants/$GRANT_ID/messages?in=sent" \
  --header "Authorization: Bearer $NYLAS_API_KEY"
Enter fullscreen mode Exit fullscreen mode

If the copy is in Sent but never arrived, you're debugging deliverability; if it's not in Sent, you're debugging config. That single split cuts most debugging sessions in half.

The part transactional senders can't do

Users reply to auth emails. "I didn't request this." "My link expired." "Is this legit?" With a no-reply pipe those messages die; with this setup they land in the mailbox's inbox and fire a message.created webhook, so your app — or an agent, or a human — can respond. The reply-handling recipe shows the loop. For an auth mailbox it can be as simple as forwarding anything inbound to your support queue, which already beats silence.

Operational details worth writing down:

  • The send cap is 200 messages per account per day on the free plan. Plenty for a side project's signup volume; a busier app should move to a paid plan or split traffic across multiple accounts.
  • Put it on a subdomain. notifications.yourcompany.com isolates auth-mail reputation from your team's primary domain.
  • Rotation is grant-side first. Update settings.app_password on the grant, then paste the new value into Supabase. Live SMTP sessions drop on the next authenticated command.

Two quick questions

Port 465 or 587? Either. 465 starts encrypted (implicit TLS); 587 negotiates STARTTLS after connecting. Both run on the same host and feed the same outbound pipeline, so the choice comes down to what your network allows. Supabase's dashboard takes either value — just keep the rest of the fields identical.

Does the 30-per-hour limit still apply after switching? No — that cap belongs to Supabase's built-in development server, along with the team-members-only recipient restriction. Once custom SMTP is enabled, your sending capacity is whatever your provider allows, which for an Agent Account means 200 messages per account per day on the free plan.

Where to go from here

The complete walkthrough is in the Supabase email recipe; the Auth0 version and the broader transactional-email migration guide cover adjacent setups.

If you've got a Supabase project on the default SMTP right now, here's a fifteen-minute experiment: provision a trial-subdomain mailbox, drop it into the SMTP settings, and send yourself a magic link. Then reply to it, list the inbox via the API, and ask yourself what your app could do with that reply. That question is where this stops being plumbing and starts being product.

Top comments (0)