The API's transactional email templates, authored as React components via
react-email and exported to Liquid ({{ name }}
variables) for the Fluid-based SmtpTemplate runtime loader.
Rendered .liquid files live in Cron/SmtpTemplates/ and are committed to the
repo as static files — no Node/pnpm is needed during dotnet build or in
CI/Docker.
When you edit a template source (emails/*.tsx), re-render and commit:
pnpm install # first time only
pnpm dev # live preview at http://localhost:3000
pnpm export # overwrites Cron/SmtpTemplates/*.liquidEach exported file is a Fluid/Liquid template: line 1 is the subject, the rest
is the HTML body — the format expected by the runtime template handling in
API/Services/Email/EmailTemplate.cs / EmailServiceTemplates.
Each emails/*.tsx file should export:
- a named PascalCase React component (the parameterised template),
- a
subjectstring — emitted as the first line of the exported.liquidfile (Fluid reads line 1 as the subject template), - a
samplePropsobject — keys define which props get placeholder-substituted on export; values are used by the live preview, - a default export wrapping the component with
samplePropssoemail devcan render it.
Example:
export interface VerifyEmailProps {
'To.Name': string;
VerifyLink: string;
}
export const subject = 'Hi! Verify your Email!';
export const sampleProps: VerifyEmailProps = {
'To.Name': 'shockee',
VerifyLink: 'https://openshock.app/verify?token=preview',
};
export function EmailVerification(props: VerifyEmailProps) {
/* ... */
}
export default function Preview_EmailVerification() {
return <EmailVerification {...sampleProps} />;
}On export, prop values become {{ To.Name }} / {{ VerifyLink }} etc. Prop
names must match the variable names the API passes into Fluid at send time.
emails/*.tsx— templates (files starting with_are ignored by the exporter).emails/_lib/— shared helpers.scripts/export-templates.ts— Liquid exporter.../Cron/SmtpTemplates/*.liquid— pre-rendered templates (committed, re-generated bypnpm export).
AGPL-3.0