Authoring in TSX

Create an email definition with a portable input schema and named fixtures, then preview, check, and publish its exact source.

Install @samva/markup, @samva/vite, vite and effect in your template project. Set jsx: "react-jsx" and jsxImportSource: "@samva/markup/email" in TypeScript configuration.

emails/welcome.tsx
/** @jsxImportSource @samva/markup/email */
import { Schema } from "effect";
import { Email, Section } from "@samva/markup/email/components";
import { defineEmail } from "@samva/markup/template";

export default defineEmail({
  id: "welcome",
  schema: Schema.toStandardJSONSchemaV1(
    Schema.Struct({ firstName: Schema.String, items: Schema.Array(Schema.String) }),
  ),
  fixtures: { basic: { firstName: "Ada", items: ["Your first project"] } },
  render: (input) => ({
    subject: `Welcome, ${input.firstName}`,
    preheader: "Your account is ready",
    body: (
      <Email>
        <Section>
          <h1>Welcome, {input.firstName}</h1>
          {input.items.length > 0 && (
            <ul>{input.items.map((item) => <li key={item}>{item}</li>)}</ul>
          )}
        </Section>
      </Email>
    ),
  }),
});

Each template id is unique within the project and independent of the file name. Ids and fixture keys start with a letter, digit or underscore and continue with letters, digits, dots, underscores or hyphens. Imported helpers are ordinary modules and do not need exclusion markers.

vite.config.ts
import { defineConfig } from "vite";
import { samvaEditor } from "@samva/vite";

export default defineConfig({ plugins: [samvaEditor({ templatesDir: "emails" })] });

Run vite to preview declared fixtures. Run samva templates check before building or publishing. Commit the project dependencies and a supported lockfile: Bun text lockfile version 2 or npm lockfile version 3. Hosted builds consume that locked graph. Commit and push the checked source, then use samva templates publish --commit HEAD on a clean exact commit reachable from the fetched origin default branch. Publishing creates an immutable receipt.

buildTemplates() from @samva/vite/build returns per-entry previews and actual fixture output. The CLI build writes a version 2 JSON artifact. Imported assets require their real HTTPS serving base for check/build; local export through exportEmailProject from @samva/vite/project can instead write relative assets beside the generated pages.