MuseMVP Docs

Mail System

Complete guide to email pipeline, template development, local preview, and locale fallback rules.

MuseMVP uses Resend to send emails and React Email to render templates. The unified sendEmail() entry supports both template mode and raw mode, with locale-based email subjects.

Setup Steps


Local Preview

Use the built-in preview script to develop and test templates without sending real emails:

pnpm mail:preview

Open http://localhost:4100 in your browser to view all templates. Each template file should have a default export, and optional PreviewProps for easier testing.

Preview


Add a New Template

1. Create the template file

Create src/modules/mail/templates/account-alert.tsx:

import { Markdown } from "@react-email/components";
import { Wrapper } from "@/modules/mail/components";
import type { BaseMailProps } from "@/modules/mail/types";

export function AccountAlert({ locale, reason }: { reason: string } & BaseMailProps) {
  if (locale === "zh") {
    return (
      <Wrapper locale={locale}>
        <Markdown>账户提醒:{reason}</Markdown>
      </Wrapper>
    );
  }
  return (
    <Wrapper locale={locale}>
      <Markdown>Account alert: {reason}</Markdown>
    </Wrapper>
  );
}

AccountAlert.PreviewProps = { locale: "zh", translations: {}, reason: "demo" };
export default AccountAlert;

2. Register the template ID

Add this in src/modules/mail/templates/index.ts:

accountAlert: AccountAlert,

3. Add subject translations

Update src/i18n/translations/en/mail.json and zh/mail.json:

{
  "mail": {
    "accountAlert": {
      "subject": "[{appName}] Account Alert"
    }
  }
}

4. Call from backend

await sendEmail({
  to: user.email,
  locale,
  templateId: "accountAlert",
  context: { reason: "New device login" },
});

Common Issues

Preview works but sending fails

Check RESEND_API_KEY and verify your sender domain in Resend.

IssueSolution
Empty subjectEnsure mail.<templateId>.subject exists in mail.json
Template not foundRegister it in src/modules/mail/templates/index.ts