/** * Renders the email carrying a password reset link. `requestPasswordReset` * (`password-reset-service.ts`) sends it, in the instance's style and * language: whoever asks isn't signed in, so their own settings don't apply. * * @module */ import { OG_SITE_NAME } from "../config.ts"; import { i18n } from "./i18n.ts"; import { EmailKit, escMd, lookOf, mdLink, type RenderedEmail, } from "./layout.ts"; /** * Returns the reset email of `username`, whose button opens `resetUrl`. The * link stays usable for `hours`, which the email states. */ export function renderPasswordResetEmail( username: string, resetUrl: string, hours: number, ): RenderedEmail { const markdown = [ `# ${ escMd(i18n._({ id: "email.reset.title", message: "Reset your password" })) }`, escMd(i18n._({ id: "email.reset.hi", message: "Hi {username},", values: { username }, })), escMd(i18n._({ id: "email.reset.body", message: "Someone asked to reset the password of your {site} account. The button below lets you choose a new one. It works once, for {hours, plural, one {# hour} other {# hours}}.", values: { site: OG_SITE_NAME, hours }, })), mdLink( i18n._({ id: "email.reset.button", message: "Reset password" }), resetUrl, ), `*${ escMd(i18n._({ id: "email.reset.fallback", message: "If the button doesn't work, paste this link into your browser:", })) }*`, "```\n" + resetUrl + "\n```", `*${ escMd(i18n._({ id: "email.reset.ignore", message: "If you didn't ask for this, ignore this email. Your password stays the same.", })) }*`, "---", escMd(i18n._({ id: "email.reset.reason", message: "You're getting this email because a password reset was requested for this address.", })), ].join("\n\n"); return new EmailKit(lookOf()).render({ subject: i18n._({ id: "email.reset.subject", message: "Reset your {site} password", values: { site: OG_SITE_NAME }, }), preheader: i18n._({ id: "email.reset.preheader", message: "The link works once, for {hours, plural, one {# hour} other {# hours}}.", values: { hours }, }), markdown, }); }