@siax/email (0.2.0)
Installation
@siax:registry=https://git.cloud.siax.io/api/packages/sax3l/npm/npm install @siax/email@0.2.0"@siax/email": "0.2.0"About this package
@siax/email
Canonical, reusable email component/design package for every SIAX email
surface (AE-002/AE-003/AE-005). React Email components, five ready-made
layouts, a deterministic render-to-HTML/text pipeline and a sha256 checksum
contract — built on @react-email/components
(0.0.39 / renderer 1.1.0, the 6.9.x-era packages).
Canonical ownership
| Concern | Owner |
|---|---|
| Visual primitives (components, layouts, tokens) | DES1GN / @siax/email (this package) |
| Business rendering orchestration (which template, for whom, locale, data, link tokens, sending) | N0TIFY |
renderEmail lives here, template truth lives in N0TIFY. Rendering
machinery (element tree → deterministic HTML/text → checksum) is a design-
system capability with exactly one implementation; which template a recipient
gets, with which data and which link tokens, is business logic that belongs to
N0TIFY. N0TIFY composes @siax/email layouts + components into trees and
calls compileEmail; it must never re-implement rendering, and DES1GN must
never invent templates.
Hard constraints (enforced by the components themselves)
- Table-based layout — email clients ignore div layout.
- Inline styles only — the
<style>element is legal ONLY insideEmailDocument's head (media queries for mobile column collapse; dark-mode meta tags live there too). Components never emit<style>. - No JavaScript, no forms — email is a static medium.
- Escaped by default — React escapes all children; the only raw-markup
islands are the package-authored Outlook conditional comments (VML), whose
interpolated props pass through
escapeHtmlfirst. - All colors/spacing/typography from
tokens/— plain hex/px because email clients do not support OKLCH/modern CSS; these are the email-surface projection of the SIAX semantic tokens.
Bulletproof Outlook support
Outlook desktop (Word rendering engine) ignores CSS padding/border-radius on
anchors and all background-image CSS. Two components carry explicit opt-in
fallbacks:
EmailButton outlookFallback— emits a mso-conditional VMLv:roundrectalongside the padded table-cell anchor; the anchor is mso-hidden so Outlook never paints both.EmailBackground outlookVml— wraps children in a mso-conditionalv:rect+v:fill type="frame"so Outlook desktop paints the image.
import { EmailButton } from '@siax/email';
<EmailButton href="{{confirmUrl}}" outlookFallback>
Bekräfta min e-post
</EmailButton>
Usage
import { EmailSecurityLayout, EmailOtp, compileEmail } from '@siax/email';
const compiled = await compileEmail({
subject: 'Din verifieringskod',
preheader: 'Koden gäller i 10 minuter',
templateVersion: 'n0tify/login-otp@2',
locale: 'sv-SE',
element: (
<EmailSecurityLayout heading="Din verifieringskod" lead="Ange koden i appen.">
<EmailOtp code="492 811" label="Din engångskod" expiresInMinutes={10} />
</EmailSecurityLayout>
),
});
// compiled.html / compiled.text / compiled.subject
// compiled.metadata.checksum — sha256(html + text), deterministic
Layouts
| Layout | Footer | Unsubscribe |
|---|---|---|
EmailTransactionalLayout |
identity | no (operationally mandatory mail) |
EmailNotificationLayout |
identity | consumer-supplied via footer slot |
EmailSecurityLayout |
none | impossible — the props do not exist |
EmailInvoiceLayout |
identity | no |
EmailMarketingLayout |
identity | REQUIRED props — cannot compose without them |
Testing
pnpm -F @siax/email test # vitest, deterministic-render assertions
The render test asserts byte-identical output for repeated renders of the same tree (same checksum twice) — the property N0TIFY's queue dedup and the aud0 trail rely on.
Dependencies
Dependencies
| ID | Version |
|---|---|
| @react-email/components | 0.0.39 |
| @react-email/render | 1.1.0 |
Development Dependencies
| ID | Version |
|---|---|
| @eslint/js | ^10.0.1 |
| @siax/config | 0.2.1 |
| @testing-library/dom | ^10.4.1 |
| @testing-library/react | ^16.3.2 |
| @types/node | ^22.10.0 |
| @types/react | ^19.2.0 |
| @types/react-dom | ^19.2.0 |
| @vitejs/plugin-react | ^4.7.0 |
| eslint | ^10.0.0 |
| eslint-plugin-react-hooks | ^7.1.0 |
| globals | ^17.0.0 |
| jsdom | ^30.0.1 |
| react | ^19.2.0 |
| react-dom | ^19.2.0 |
| typescript | ^5.7.2 |
| typescript-eslint | ^8.66.0 |
| vitest | ^3.0.0 |
Peer Dependencies
| ID | Version |
|---|---|
| react | ^19.2.0 |
| react-dom | ^19.2.0 |