Skip to content
Groundmail

Free email template

Email verification email template

Confirms a new address after sign-up or an email change. 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 email verification email needs.

The template covers the first four and the sixth. The fifth lives in your app, next to the sign-up form.

  1. Why they're getting it

    Someone just typed this address into a form. Say what the confirmation is for, finishing account setup, so the real owner knows what happens if they click.

  2. One confirm button

    A single action, worded as what it does. No welcome tour, no links to your blog: those belong in the next email, once you know the address is real.

  3. A longer expiry than a reset

    People verify later, often from another device. The template's example is 24 hours. Say how long it lasts so an expired link isn't a surprise.

  4. An "ignore this" line

    Typos send verification emails to strangers. Tell them that if they didn't create an account, they can ignore the email and nothing is set up.

  5. A resend button in your app

    Links expire and emails get filtered. Put a rate-limited Resend button on the screen that waits for verification, and let people fix a mistyped address there.

  6. A link people can paste

    The full URL sits under the button and in the plain-text part, for clients that block buttons or people who verify on another device.

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 { Button, Divider, Layout, LinkFallback, P, Small, Title } from '../../components'
import type { TemplateMeta } from '../../components/meta'
import { plainText } from '../../components/text'

export type EmailVerificationProps = {
  name: string
  verifyUrl: string
  expiresIn: string
}

export const meta: TemplateMeta = {
  name: 'Email verification',
  description: 'Confirms a new address after sign-up or an email change.',
  group: 'Authentication',
  subject: 'Confirm your email address',
}

export default function EmailVerification({ name, verifyUrl, expiresIn }: EmailVerificationProps) {
  return (
    <Layout
      preview="Confirm your email address to finish setting up your account."
      footerNote="You're receiving this because this address was used to create an account."
    >
      <Title>Confirm your email address</Title>
      <P>Hi {name},</P>
      <P>Confirm that this is your email address to finish setting up your account.</P>
      <Button href={verifyUrl}>Confirm email address</Button>
      <Small>
        This link expires in {expiresIn}. If you didn't create an account, you can ignore this email.
      </Small>
      <Divider />
      <LinkFallback href={verifyUrl} />
    </Layout>
  )
}

EmailVerification.PreviewProps = {
  name: 'Ada',
  verifyUrl: 'https://example.com/verify-email?token=2b7d91',
  expiresIn: '24 hours',
} satisfies EmailVerificationProps

export function text({ name, verifyUrl, expiresIn }: EmailVerificationProps) {
  return plainText(
    'Confirm your email address',
    `Hi ${name},`,
    'Confirm that this is your email address to finish setting up your account:',
    verifyUrl,
    `This link expires in ${expiresIn}. If you didn't create an account, you can ignore this email.`,
  )
}

email-verification.tsx, 52 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/email-verification/email-verification.html \
  --alias email-verification \
  --name "Email verification" \
  --subject "Confirm your email address" \
  --text templates/email-verification/email-verification.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: 'email-verification',
    variables: {
      name: 'Ada',
      verify_url: 'https://example.com/verify-email?token=2b7d91',
      expires_in: '24 hours',
    },
  },
})

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

Say what you need them to do. The template's default leaves the product name out, so consider one of the alternatives if your sender name is a person or a generic address.

  • Confirm your email addressDefaultPlain and direct. Your sender name carries the brand.
  • Confirm your email for AcmeGoodAdds the product, which helps when people sign up for several things in a day.
  • Acme: verify your email addressGoodBrand first, for people who scan the inbox by sender.
  • Action required: verify now or lose accessAvoidA threat in a first email reads as phishing, and new accounts have no access to lose yet.

A verification email in spam is a sign-up you never finish

The email has to arrive while people are still on your sign-up screen, or they move on and forget. Sign-up forms also collect plenty of mistyped addresses.

What a 550 5.1.1 bounce means →
  • Send from your own domain with SPF, DKIM and DMARC set up.
  • Keep it on a transactional stream, apart from newsletters and marketing.
  • Suppress addresses that hard-bounce, and show the person a "check your address" message instead of retrying.
  • 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.