# One-time passcode email template

URL: https://samva.dev/templates/one-time-passcode

Put a short-lived login code at the center of the email, with the request spelled out. Open Linear login code for a magic-link send with a fallback code.

## Guidance

- The code is the only thing above the fold. This send carries no login link, so a recipient reading on a phone sees the digits first.
- State the expiry window in the input. The template never reads the clock. Pass the request details as a list so the recipient can recognise the attempt as their own.
- Set the new-device block only when the attempt came from a browser the account has not used, so the warning stays rare enough to be believed.
- Edit the passcode email in the AI email editor. Use Linear login code when the send needs a magic link plus a fallback code.

## Variables

| Variable | Meaning |
| --- | --- |
| code | The one-time code as a string, for example “482913”. Preserve leading zeroes and never reuse the preview value for real sign-ins. |
| expiryNotice | For example: “The code stops working 10 minutes after it was sent.” Derive this copy from the actual server-side expiry policy. |
| helpUrl | A sign-in help page, for example https://northloop.example/help/sign-in, accessible when the recipient cannot sign in. |
| newDevice | Optional object with label and detail strings. Omit unless your application identified a new device; the template does not perform device detection. |
| requestDetails | A list of { label, value } objects, for example { "label": "Device", "value": "Chrome on macOS" }. Use recorded context, not guessed location or device identity. |
| workspace | The product or workspace being accessed, for example “Acme Studio”. |

## Choose the Code Variant

Routine sign-in: omit newDevice and keep the code prominent. The starter has no login button, so it works for someone reading email on a different device from the sign-in form.

New-device sign-in: populate newDevice with a short title and explanation only when your application has evidence for that state. Request context helps someone recognize an attempt; it does not authenticate the device.

Verification or recovery code: change the subject and body to name the actual action before reusing this design. A sign-in code must not silently double as an address-verification or password-reset credential.

## Handle Resends and Wrong Codes

Your application generates the code, binds it to the intended account and purpose, limits verification attempts, and enforces expiry and one-time use. The template displays the value supplied to it. Its ten-minute preview is example data, not an enforced lifetime.

Decide whether resending keeps the active code or invalidates it and issues another. Explain the policy on the code-entry screen, and test delayed delivery so an older email cannot mislead someone about which code is valid.

For an unsolicited code, tell the recipient not to share it or enter it for a request they did not start. Keep helpUrl usable outside the signed-in session. Test leading zeroes, the wrong code, an expired code, reuse after success, and the attempt limit before launch.

## Connect an OTP Callback

The Better Auth integration includes an emailOTP callback. Pass the callback’s code to the code input and preserve the operation type when selecting your email copy. Its built-in emails are separate from this gallery starter; a template override is the bridge to your customized design.

Keep API keys and code verification on the server. Render and send the email from the auth callback, then let the authentication library decide whether the submitted code creates a session.

## Implementation Guides

- [Send Authentication Emails With Better Auth](/docs/integrations/better-auth): Connect password reset, verification, and one-time codes to your authentication callbacks.
