Skip to content
Groundmail

Free email template

One-time code email template

A large, copyable verification code for 2FA, sign-in or checkout confirmation. Free and MIT-licensed, in React Email, MJML, HTML and plain text, with light and dark mode built in.

  • MIT license
  • Works with any email provider
  • Light and dark mode

What every one-time code email needs.

This template does all six. If you write your own, check it against this list.

  1. The code in the subject

    Phones show the subject in the notification, so people can read the code without leaving the screen they're on. The template's subject starts with it.

  2. Big, plain and easy to select

    Large monospace digits in a box of their own. Nothing else in the email should look like a code, so copying it takes one tap.

  3. A short expiry

    Ten minutes is common for sign-in and 2FA codes. Say it, so someone who comes back later asks for a new code instead of guessing.

  4. A line about sharing

    Scammers phone people and ask them to read out the code. The template says you'll never ask for it by phone, chat or email.

  5. What an unexpected code means

    A code nobody asked for often means someone has the password. The template says so, and tells them to change it.

  6. No button to click

    A code email doesn't need a button or tracking links. The template's only link is your logo, which leaves filters little to score and phishers nothing to copy.

The code. Copy the format your stack uses.

Change the brand name, logo and colors once in theme.ts and every template follows.

import * as React from 'react'
import { Code, Layout, P, Small, Title } from '../../components'
import type { TemplateMeta } from '../../components/meta'
import { plainText } from '../../components/text'
import { theme } from '../../theme'

export type OneTimeCodeProps = {
  code: string
  expiresIn: string
}

export const meta: TemplateMeta = {
  name: 'One-time code',
  description: 'A large, copyable verification code for 2FA, sign-in or checkout confirmation.',
  group: 'Authentication',
  subject: `{{code}} is your ${theme.brand.name} verification code`,
}

export default function OneTimeCode({ code, expiresIn }: OneTimeCodeProps) {
  return (
    <Layout
      preview={`Your verification code is ${code}. It expires in ${expiresIn}.`}
      footerNote="You're receiving this because a verification code was requested for your account."
    >
      <Title>Your verification code</Title>
      <P>Enter this code to continue:</P>
      <Code>{code}</Code>
      <Small>
        The code expires in {expiresIn}. We will never ask you for this code by phone, chat or email, so don't
        share it with anyone.
      </Small>
      <Small style={{ margin: 0 }}>
        Didn't request a code? Someone may know your password. Change it to keep your account safe.
      </Small>
    </Layout>
  )
}

OneTimeCode.PreviewProps = {
  code: '482913',
  expiresIn: '10 minutes',
} satisfies OneTimeCodeProps

export function text({ code, expiresIn }: OneTimeCodeProps) {
  return plainText(
    'Your verification code',
    `Enter this code to continue: ${code}`,
    `The code expires in ${expiresIn}. We will never ask you for this code by phone, chat or email, so don't share it with anyone.`,
    "Didn't request a code? Someone may know your password. Change it to keep your account safe.",
  )
}

one-time-code.tsx, 51 lines, shown in full (scroll inside the panel). Typed props. Copy it with theme.ts and components/ from the repo. View on GitHub

Send it with Groundmail

Create the template in your account once, then send it by alias from your app.

1Terminal
npx -y --package=groundmail-cli -- groundmail templates push templates/one-time-code/one-time-code.html \
  --alias one-time-code \
  --name "One-time code" \
  --subject "{{code}} is your Acme verification code" \
  --text templates/one-time-code/one-time-code.txt \
  --publish
2Node.js
import { Groundmail } from 'groundmail'

const groundmail = new Groundmail(process.env.GROUNDMAIL_API_KEY!)

await groundmail.emails.send({
  from: 'Acme <noreply@yourdomain.com>',
  to: 'ada@example.com',
  template: {
    id: 'one-time-code',
    variables: {
      code: '482913',
      expires_in: '10 minutes',
    },
  },
})

The CLI command and the Node.js send from the template's README, which also has Python, PHP and cURL. View on GitHub

Subject lines

Lead with the code if you're comfortable with it showing on a locked phone. If not, keep the code in the body and the subject plain.

  • {{code}} is your Acme verification codeDefaultThe code is readable straight from the notification, and the product name says where it's for.
  • Your Acme code: {{code}}GoodThe same idea, shorter, for narrow notification previews.
  • Your Acme verification codeGoodKeeps the code off the lock screen, for accounts where that matters more than speed.
  • Your code is insideAvoidHides the one thing people need, and a teaser subject reads like bait.

A code that arrives after it expires is no code at all

Ten minutes is short when an email sits in a queue or a spam folder. Code emails need to arrive in seconds, every time.

SPF, DKIM and DMARC for transactional email →
  • Send from your own domain with SPF, DKIM and DMARC set up.
  • Keep it on a transactional stream, apart from newsletters and marketing.
  • Throttle code requests per account and per address, so a bot can't use your form to flood an inbox.
  • Groundmail sends this template by alias from your own domain, on our own mail servers. Send it with Groundmail

Questions

Is it free to use?

Yes. The templates are MIT-licensed: use them in commercial products and change them however you like.

Do I need Groundmail to use it?

No. The HTML and text files use plain placeholders that work with most providers' template engines and with Handlebars or Mustache. Sending through Groundmail just saves a step.

Does it work in dark mode and Outlook?

Yes. The full HTML file carries dark-mode styles for Apple Mail and Outlook.com, and the extra markup desktop Outlook needs to draw the button.

How do I change the colors and logo?

Edit theme.ts once (name, logo, address and colors for light and dark) and rebuild. Every template in the set picks it up.

Is it safe to put the code in the subject line?

It's a trade-off. The code shows on lock-screen notifications, which is faster for the person and visible to anyone holding their phone. The template's default subject includes it; if your codes guard something sensitive, use a subject without {{code}} and keep it in the body.