# Customize Supabase authentication emails

Choose dashboard templates or the Send Email Hook, preview six authentication flows, and test signatures and email-change mappings locally.

Author: Stampwing
Canonical: https://www.stampwing.com/guides/supabase-auth-email-templates
Published: 2026-10-05
Reviewed: 2026-10-05
Category: Templates

Preview all authentication email flows and verify recipient/token mappings before enabling a global hook.

## Short answer

Section link: https://www.stampwing.com/guides/supabase-auth-email-templates#short-answer

Use dashboard templates when Supabase sends through SMTP. Use the Send Email Hook when your code needs to render and send through an email service. An enabled hook takes over sending, so handle every supported authentication action and verify its signature before reading or using tokens.

## Before you start

Section link: https://www.stampwing.com/guides/supabase-auth-email-templates#before-you-start

For: Developers building and operating application email.

Bring: Node.js 22+, npm, and the pinned standardwebhooks dependency. A Supabase project is only needed for the later setup steps.

Scope: The download runs locally with synthetic data. All email delivery is simulated; no provider credentials or live sends are needed.

## Choose which system renders the email

Section link: https://www.stampwing.com/guides/supabase-auth-email-templates#choose-the-path

Changing a dashboard template and enabling the Send Email Hook are different integration paths. With SMTP sending, Supabase renders its configured templates. With the hook enabled, your handler takes responsibility for rendering and sending. Dashboard edits will not automatically change the HTML that your hook constructs.

Start with the simpler SMTP/template path if layout and wording are the only changes you need. Choose a hook for custom rendering, routing, or other application logic. Keep the email provider enabled in Supabase; a hook does not turn disabled email signup into an enabled flow.

The ZIP contains HTML and plain-text previews produced by the hook renderer. They are not Go-template source to paste directly into Supabase’s dashboard. Translate variables into the dashboard’s documented syntax if you choose that separate path.

The local hook accepts the dashboard’s v1,whsec_ signing-secret prefix. Error responses carry an error object with an HTTP code and message; unsupported actions and incomplete email-change payloads cannot return a success.

## Exercise signed hook requests without a Supabase project

Section link: https://www.stampwing.com/guides/supabase-auth-email-templates#run-locally

Run npm ci, npm test, and npm run demo after extracting the ZIP. The demo signs a synthetic email-change payload with an obvious fixture secret and passes the original request body through the same verification library used by the local handler.

Run node write-previews.mjs to refresh the templates directory. It contains signup, recovery, magic-link, invitation, current/new email-change, and reauthentication previews. Open the HTML files locally; the confirmation destinations are illustrative and no confirmation server is included.

Run from the extracted example folder

```sh
npm ci
npm test
npm run demo
```

## Read the key part of the example

Section link: https://www.stampwing.com/guides/supabase-auth-email-templates#example-source

This excerpt comes from hook.mjs, lines 49–68, in the download. It shows the central decision; run the complete package with the commands above.

Local simulation · hook.mjs

```javascript
  if (action === "email_change") {
    if (
      !address(user.new_email) ||
      user.new_email.toLowerCase() === user.email.toLowerCase()
    )
      throw Error("Invalid new recipient");
    // Supabase's backwards-compatible mapping: *_new hash belongs to CURRENT email.
    recipients = d.token_hash_new
      ? [
          { to: user.email, token: d.token, hash: d.token_hash_new },
          { to: user.new_email, token: d.token_new, hash: d.token_hash },
        ]
      : [
          {
            to: user.new_email,
            token: d.token_new || d.token,
            hash: d.token_hash,
          },
        ];
  }
```

## Find the files you’ll change

Section link: https://www.stampwing.com/guides/supabase-auth-email-templates#example-files

Pinned dependencies: standardwebhooks 1.1.1. Install with npm ci so the lockfile controls the resolved versions.

| File | Purpose |
| --- | --- |
| hook.mjs | The example behavior shown in this article. |
| test.mjs | Acceptance checks and synthetic failure cases. |
| demo.mjs / expected-output.json | A repeatable local experiment and its recorded result. |
| README.md | Setup commands, expected behavior and production boundaries. |
| BUILD-BRIEF.md | The coding-agent brief below. |
| package.json / package-lock.json | Pinned dependencies and runnable commands. |
| LICENSE | MIT license for adapting this example. |

## Compare the recorded local result

Section link: https://www.stampwing.com/guides/supabase-auth-email-templates#recorded-experiment

Captured from this package’s demo command on October 5, 2026. These results use synthetic fixtures and simulated delivery; they do not measure a live provider or inbox placement.

Recorded local simulation · expected-output.json

```json
{
  "simulated": true,
  "recipients": [
    {
      "to": "current@example.test",
      "tokenHash": "hash-for-current"
    },
    {
      "to": "new@example.test",
      "tokenHash": "hash-for-new-or-single"
    }
  ]
}
```

## Cover the full authentication lifecycle

Section link: https://www.stampwing.com/guides/supabase-auth-email-templates#cover-every-action

| Action | Email behavior |
| --- | --- |
| signup | Confirm the initial address. |
| recovery | Start account recovery; the app completes the password change. |
| magiclink | Offer the sign-in link or code. |
| invite | Let the invited person accept in the application. |
| email_change | Map the correct token and hash to each required recipient. |
| reauthentication | Present a code to enter in the app. |

## Check the counterintuitive email-change mapping

Section link: https://www.stampwing.com/guides/supabase-auth-email-templates#email-change

With secure email change enabled, user.email is the current address and user.new_email is the replacement. Supabase’s compatibility mapping associates token_hash_new with the current address and token; token_hash belongs to the new address and token_new. Do not interpret the _new suffix on the hash as the destination.

The local tests assert both recipients and both code/hash pairs. They also cover the single-recipient flow when the second hash is absent. Missing required values and unknown action types return an error; the handler cannot silently acknowledge a flow it did not render.

## Reject unsafe requests before capture

Section link: https://www.stampwing.com/guides/supabase-auth-email-templates#failure-cases

The handler verifies the raw body with Standard Webhooks, including signature freshness. Reformatting JSON before verification changes the signed bytes. Only after verification does the renderer inspect the action, destination addresses, and approved redirect.

A failed local capture returns a retryable failure instead of a successful acknowledgement. The callback in this educational lab is not a durable queue, and repeated valid requests can be captured repeatedly. Use a persisted operation identity and durable storage before putting this pattern behind a real Supabase hook.

## Connect the selected path in Supabase

Section link: https://www.stampwing.com/guides/supabase-auth-email-templates#production-setup

For SMTP, configure the provider connection, verify the sending identity, and update each dashboard template using Supabase’s supported variables. For a hook, deploy your authenticated HTTPS handler, configure its signing secret, replace the local capture with a durable delivery operation, and enable the Send Email Hook in Auth settings.

Keep real tokens and secrets out of logs. Allowlist your own callback origins and paths. The sample /confirm URL is a placeholder: your application must implement the verification step using the documented Supabase token type and hash before establishing a session or completing a change.

Test the whole account journey in a separate environment: verification, recovery, invitation, both email-change modes, and reauthentication. A successfully rendered email does not establish that the destination flow works. Keep provider setup and live delivery checks separate from the offline lab.

[Understand scanner visits to magic links](https://www.stampwing.com/guides/magic-link-expired-before-click)

## Can I turn on the hook for password resets only?

Section link: https://www.stampwing.com/guides/supabase-auth-email-templates#common-question

The Send Email Hook takes responsibility for the authentication email flows handled by the hook. Keep handlers for signup, recovery, magic links, invitations, email changes and reauthentication before enabling it. Test each action with the project’s actual settings.

## Use with your coding agent

Section link: https://www.stampwing.com/guides/supabase-auth-email-templates#coding-agent-brief

Download the example, then copy this brief into your coding agent. The same brief is included as BUILD-BRIEF.md.

Coding-agent build brief

```markdown
# Customize Supabase authentication emails — coding-agent brief

## Objective

Customize all six Supabase authentication actions with HTML/text rendering and a locally verified Send Email Hook.

## Read first

Read README.md, package.json, hook.mjs, test.mjs and demo.mjs. Keep dependency versions pinned to package-lock.json. Use Node.js 22+.

## Dependencies

standardwebhooks 1.1.1. Install with npm ci and preserve the lockfile.

## Work

Start at `renderEmails` in hook.mjs. Run the existing synthetic fixtures before changing behavior. Preserve the guide's original scenario and add a regression check for each changed failure case.

## Constraints

All email is simulated. Do not add provider credentials, send email, deploy services, or use the application's database. Preserve unknown outcomes instead of claiming delivery. Do not turn the local demonstration into production authentication or a public mail relay. Explain the production setup separately.

## Verification

Run `npm ci`, `npm test`, and `npm run demo`.

## Acceptance

Check all six actions and both email-change modes. Verify dashboard-prefixed secrets, wrong and stale signatures, incomplete token pairs, unsupported actions and rejected redirects. Never acknowledge failed capture as success.
No real tokens, signing secrets, or recipient data appear in logs. All fixtures use synthetic values.
```

## Check the download

Section link: https://www.stampwing.com/guides/supabase-auth-email-templates#download-integrity

The ZIP contains 16,197 bytes. Compare its SHA-256 digest with this value before extracting. Downloads are free and require no signup.

SHA-256 · supabase-auth-email-templates.zip

```text
feea9b5fd210800a1902f445cbf74ebbad4d5a68cfce73a4ee80ea7beb0a3fe8
```

## Sources

Section link: https://www.stampwing.com/guides/supabase-auth-email-templates#sources

- [Supabase: Send Email Hook and email-change mapping](https://supabase.com/docs/guides/auth/auth-hooks/send-email-hook)
- [Supabase: email templates](https://supabase.com/docs/guides/auth/auth-email-templates)
- [Supabase: redirect URLs](https://supabase.com/docs/guides/auth/redirect-urls)
- [Standard Webhooks specification](https://github.com/standard-webhooks/standard-webhooks/blob/main/spec/standard-webhooks.md)

Example download: [Download the local example](https://www.stampwing.com/downloads/supabase-auth-email-templates.zip)

## Related guides

- https://www.stampwing.com/guides/magic-link-expired-before-click
- https://www.stampwing.com/guides/password-reset-email-templates
- https://www.stampwing.com/guides/reliable-email-webhooks

Editorial policy: https://www.stampwing.com/resources/editorial
