Skip to content
Groundmail

Free email template

New sign-in alert email template

A security alert for a sign-in from a new device, with details and a "secure my account" path. 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 new sign-in alert email needs.

The template covers the email side of all six. Points 1 and 5 also depend on your app.

  1. Only for new devices

    Send it when a device or browser signs in for the first time, not on every sign-in. An alert people see daily is an alert they stop reading.

  2. Details people can recognise

    Time with a time zone, device and browser, a rough location and the IP address. Enough for someone to say "that was me" or "that wasn't".

  3. Say the location is approximate

    Locations from an IP address can be a city or more off. The template says so, which saves a lot of worried support emails.

  4. Nothing to do if it was them

    Most alerts are the account owner on a new laptop. Say plainly that there's nothing to do, so people don't panic.

  5. One path for "this wasn't me"

    The template's button promises to help change the password and sign out every other session. Make sure the page behind it does both.

  6. Nothing to type into the email

    Never ask for a password or a code in a security alert. Phishers copy these emails, and people should learn that the real one only ever links to your site.

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

export type NewSignInProps = {
  name: string
  signedInAt: string
  device: string
  location: string
  ipAddress: string
  secureUrl: string
}

export const meta: TemplateMeta = {
  name: 'New sign-in alert',
  description: 'A security alert for a sign-in from a new device, with details and a "secure my account" path.',
  group: 'Account',
  subject: `New sign-in to your ${theme.brand.name} account`,
}

export default function NewSignIn(props: NewSignInProps) {
  const { name, signedInAt, device, location, ipAddress, secureUrl } = props
  return (
    <Layout
      preview={`Your account was signed in to from ${device} in ${location}.`}
      footerNote="This is a security email about your account, so you get it even if other emails are turned off."
    >
      <Title>New sign-in to your account</Title>
      <P>Hi {name}, your account was just signed in to from a device we haven't seen before.</P>
      <Details
        rows={[
          ['When', signedInAt],
          ['Device', device],
          ['Location', location],
          ['IP address', ipAddress],
        ]}
      />
      <P>
        <strong>If this was you</strong>, there's nothing to do.
      </P>
      <P>
        <strong>If it wasn't</strong>, secure your account now. We'll help you change your password and sign out
        every other session.
      </P>
      <Button href={secureUrl} tone="danger">
        Secure my account
      </Button>
      <Small style={{ margin: 0 }}>Locations are estimated from the IP address and may not be exact.</Small>
    </Layout>
  )
}

NewSignIn.PreviewProps = {
  name: 'Ada',
  signedInAt: 'October 16, 2026 at 9:41 AM UTC',
  device: 'Chrome on macOS',
  location: 'Lisbon, Portugal',
  ipAddress: '203.0.113.42',
  secureUrl: 'https://example.com/account/security',
} satisfies NewSignInProps

export function text(props: NewSignInProps) {
  const { name, signedInAt, device, location, ipAddress, secureUrl } = props
  return plainText(
    'New sign-in to your account',
    `Hi ${name}, your account was just signed in to from a device we haven't seen before.`,
    textDetails([
      ['When', signedInAt],
      ['Device', device],
      ['Location', location],
      ['IP address', ipAddress],
    ]),
    "If this was you, there's nothing to do.",
    `If it wasn't, secure your account now. We'll help you change your password and sign out every other session:\n${secureUrl}`,
    'Locations are estimated from the IP address and may not be exact.',
  )
}

new-sign-in.tsx, 79 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/new-sign-in/new-sign-in.html \
  --alias new-sign-in \
  --name "New sign-in alert" \
  --subject "New sign-in to your Acme account" \
  --text templates/new-sign-in/new-sign-in.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: 'new-sign-in',
    variables: {
      name: 'Ada',
      signed_in_at: 'October 16, 2026 at 9:41 AM UTC',
      device: 'Chrome on macOS',
      location: 'Lisbon, Portugal',
      ip_address: '203.0.113.42',
      secure_url: 'https://example.com/account/security',
    },
  },
})

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

Security alerts get copied by phishers, so keep the subject factual and consistent. Name the product and say what happened.

  • New sign-in to your Acme accountDefaultFactual and specific to your product.
  • New sign-in to Acme from {{device}}GoodLets people dismiss it from the notification if they recognise the device.
  • Acme security alert: new sign-inGoodEasy to filter and search for as a security email.
  • Your account has been compromisedAvoidIt claims more than you know, frightens people who signed in themselves, and matches phishing.

A security alert only helps if it arrives while it matters

If the sign-in wasn't the account owner, the minutes after it count. And because these emails are copied by phishers, people need to be able to tell the real one apart.

SPF, DKIM and DMARC for transactional email →
  • Publish DMARC with a quarantine or reject policy, so nobody else can send alerts as your domain.
  • Keep it on a transactional stream, apart from newsletters and marketing.
  • Send from the same address as your other account emails, every time.
  • 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.