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" const magicLinkEmailLocalization = { SIGN_IN_TO_APP_NAME: "Sign in to {appName}", SIGN_IN_TO_YOUR_ACCOUNT: "Sign in to your account", YOUR_ACCOUNT: "your account", LOGO: "Logo", CLICK_BUTTON_TO_SIGN_IN: "Click the button below to sign in to your account {emailAddress}.", OR_COPY_AND_PASTE_URL: "Or copy and paste this URL into your browser:", THIS_LINK_EXPIRES_IN_MINUTES: "This link expires in {expirationMinutes} minutes.", EMAIL_SENT_BY: "Email sent by {appName}.", IF_YOU_DIDNT_REQUEST_THIS_EMAIL: "If you didn't request this email, you can safely ignore it. Someone else might have typed your email address by mistake.", POWERED_BY_BETTER_AUTH: "Powered by {betterAuth}" } /** * Localization strings for the MagicLinkEmail component. * * Contains all text content used in the magic link authentication email template. */ export type MagicLinkEmailLocalization = typeof magicLinkEmailLocalization /** * Props for the MagicLinkEmail component. */ export interface MagicLinkEmailProps { /** Magic link URL for passwordless authentication */ url: string /** Email address of the user signing in */ email?: string /** Name of the application sending the email */ appName?: string /** Number of minutes until the magic link expires */ expirationMinutes?: number /** 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 `MagicLinkEmailLocalization` */ localization?: Partial } /** * Email template component that sends magic link authentication emails for passwordless sign-in. * * This email includes: * - Sign-in button with magic link * - Fallback URL for manual copy/paste * - Expiration time information * - Security notice for unauthorized requests * - Customizable branding and styling * - Support for light/dark mode themes * * @example * ```tsx * * ``` */ export const MagicLinkEmail = ({ url, email, appName, expirationMinutes = 5, logoURL, colors, classNames, darkMode = true, poweredBy, head, ...props }: MagicLinkEmailProps) => { const localization = { ...MagicLinkEmail.localization, ...props.localization } const previewText = appName ? localization.SIGN_IN_TO_APP_NAME.replace("{appName}", appName) : localization.SIGN_IN_TO_YOUR_ACCOUNT return ( {head} {previewText}
{logoURL && (typeof logoURL === "string" ? ( {appName ) : ( <> {appName {appName ))} {appName ? localization.SIGN_IN_TO_APP_NAME.replace( "{appName}", appName ) : localization.SIGN_IN_TO_YOUR_ACCOUNT} {(() => { const [beforeEmailAddress, afterEmailAddress] = localization.CLICK_BUTTON_TO_SIGN_IN.split("{emailAddress}") return email ? ( <> {beforeEmailAddress} {email} {afterEmailAddress} ) : ( localization.CLICK_BUTTON_TO_SIGN_IN.replace( "{emailAddress}", "" ) .replace(/\s{2,}/g, " ") .replace(" .", ".") ) })()}
{localization.OR_COPY_AND_PASTE_URL} {url}
{expirationMinutes || appName ? ( {expirationMinutes ? localization.THIS_LINK_EXPIRES_IN_MINUTES.replace( "{expirationMinutes}", expirationMinutes.toString() ) : null} {appName && ( <> {expirationMinutes ? " " : ""} {localization.EMAIL_SENT_BY.replace("{appName}", appName)} )} ) : null} {localization.IF_YOU_DIDNT_REQUEST_THIS_EMAIL} {poweredBy && ( {(() => { const [beforeBetterAuth, afterBetterAuth] = localization.POWERED_BY_BETTER_AUTH.split("{betterAuth}") return ( <> {beforeBetterAuth} better-auth {afterBetterAuth} ) })()} )}
) } MagicLinkEmail.localization = magicLinkEmailLocalization MagicLinkEmail.PreviewProps = { url: "https://better-auth-ui.com/auth/verify?token=example-token", email: "m@example.com", appName: "Better Auth", darkMode: true } as MagicLinkEmailProps export default MagicLinkEmail