import { Body, Button, Container, Head, Heading, Hr, Html, Img, Link, Preview, pixelBasedPreset, Section, Tailwind, Text } from "@react-email/components" import type { ReactNode } from "react" import { cn } from "../../../lib/utils" import { type EmailClassNames, type EmailColors, EmailStyles } from "./email-styles" /** * Device information displayed in the new device email notification. */ export interface DeviceInfo { /** Browser name and version */ browser?: string /** Operating system name and version */ os?: string /** Geographic location of the sign-in */ location?: string /** IP address of the device */ ipAddress?: string /** Timestamp of the sign-in event */ timestamp?: string } const newDeviceEmailLocalization = { NEW_SIGN_IN_DETECTED: "New sign-in detected", LOGO: "Logo", NEW_SIGN_IN_TO_YOUR_ACCOUNT: "We detected a new sign-in to your {appName} account {userEmail} from a device we don't recognize.", DEVICE_DETAILS: "Device details", BROWSER: "Browser", OPERATING_SYSTEM: "Operating System", LOCATION: "Location", IP_ADDRESS: "IP Address", TIME: "Time", IF_THIS_WAS_YOU: "If this was you, you can safely ignore this email. If you don't recognize this activity, please secure your account immediately.", SECURE_MY_ACCOUNT: "Secure my account", EMAIL_SENT_BY: "Email sent by {appName}.", IF_YOU_DIDNT_SIGN_IN: "If you didn't sign in, please contact support immediately {supportEmail} to secure your account.", POWERED_BY_BETTER_AUTH: "Powered by {betterAuth}" } /** * Localization strings for the NewDeviceEmail component. * * Contains all text content used in the new device detection email template. */ export type NewDeviceEmailLocalization = typeof newDeviceEmailLocalization /** * Props for the NewDeviceEmail component. */ export interface NewDeviceEmailProps { /** Email address of the user account */ userEmail?: string /** Information about the device that signed in */ deviceInfo?: DeviceInfo /** URL to secure the account if unauthorized access is suspected */ secureAccountLink?: string /** Name of the application sending the email */ appName?: string /** Support email address for security concerns */ supportEmail?: string /** Logo URL(s) - a single string or light/dark variants. If omitted, no logo is shown. */ logoURL?: string | { light: string; dark: string } /** Custom CSS class names for styling specific parts of the email */ classNames?: EmailClassNames /** Custom color scheme for light and dark modes */ colors?: EmailColors /** Whether to show the "Powered by better-auth" footer */ poweredBy?: boolean /** Whether to enable dark mode support */ darkMode?: boolean /** Additional React nodes to inject into the email head */ head?: ReactNode /** * Localization overrides for customizing email text * @remarks `NewDeviceEmailLocalization` */ localization?: Partial } /** * Email template component that notifies users when a new device signs into their account. * * This email includes: * - Device information display (browser, OS, location, IP, timestamp) * - Secure account action button * - Security warnings and support contact information * - Customizable branding and styling * - Support for light/dark mode themes * * @example * ```tsx * * ``` */ export const NewDeviceEmail = ({ userEmail, deviceInfo, secureAccountLink, appName, supportEmail, logoURL, colors, classNames, darkMode = true, poweredBy, head, ...props }: NewDeviceEmailProps) => { const localization = { ...NewDeviceEmail.localization, ...props.localization } const previewText = localization.NEW_SIGN_IN_DETECTED return ( {head} {previewText}
{logoURL && (typeof logoURL === "string" ? ( {appName ) : ( <> {appName {appName ))} {localization.NEW_SIGN_IN_DETECTED} {(() => { const textWithAppName = localization.NEW_SIGN_IN_TO_YOUR_ACCOUNT.replace( "{appName}", appName || "" ) .replace(/\s{2,}/g, " ") .replace(" .", ".") const [beforeUserEmail, afterUserEmail] = textWithAppName.split("{userEmail}") return userEmail ? ( <> {beforeUserEmail} {userEmail} {afterUserEmail} ) : ( textWithAppName .replace("{userEmail}", "") .replace(/\s{2,}/g, " ") .replace(" .", ".") ) })()} {deviceInfo && (
{localization.DEVICE_DETAILS}: {deviceInfo.browser && ( {localization.BROWSER}: {" "} {deviceInfo.browser} )} {deviceInfo.os && ( {localization.OPERATING_SYSTEM}: {" "} {deviceInfo.os} )} {deviceInfo.location && ( {localization.LOCATION}: {" "} {deviceInfo.location} )} {deviceInfo.ipAddress && ( {localization.IP_ADDRESS}: {" "} {deviceInfo.ipAddress} )} {deviceInfo.timestamp && ( {localization.TIME}: {" "} {deviceInfo.timestamp} )}
)} {localization.IF_THIS_WAS_YOU} {secureAccountLink && (
)}
{appName && ( {localization.EMAIL_SENT_BY.replace("{appName}", appName)} )} {(() => { const [beforeSupportEmail, afterSupportEmail] = localization.IF_YOU_DIDNT_SIGN_IN.split("{supportEmail}") return supportEmail ? ( <> {beforeSupportEmail} {supportEmail} {afterSupportEmail} ) : ( localization.IF_YOU_DIDNT_SIGN_IN.replace( "{supportEmail}", "" ) .replace(/\s{2,}/g, " ") .replace(" .", ".") ) })()} {poweredBy && ( {(() => { const [beforeBetterAuth, afterBetterAuth] = localization.POWERED_BY_BETTER_AUTH.split("{betterAuth}") return ( <> {beforeBetterAuth} better-auth {afterBetterAuth} ) })()} )}
) } NewDeviceEmail.localization = newDeviceEmailLocalization NewDeviceEmail.PreviewProps = { userEmail: "m@example.com", deviceInfo: { browser: "Chrome on macOS", os: "macOS 26.2", location: "San Francisco, CA, United States", ipAddress: "127.0.0.1", timestamp: "February 10, 2025 at 4:20 PM UTC" }, secureAccountLink: "https://better-auth-ui.com/auth/secure-account", appName: "Better Auth", supportEmail: "support@example.com", darkMode: true } as NewDeviceEmailProps export default NewDeviceEmail