Brands
Give every template your organization's colors, fonts, logo, and footer by importing a brand, and republish when the brand changes.
A brand is how your organization's email looks and signs off. It has three parts:
- Theme: the colors, fonts, text sizes, and corners templates use, written as CSS theme variables.
- Logo and icon: a light logo, a dark logo, and a square icon, each an https URL.
- Footer: your company name, postal address, and social links.
Your organization has one default brand and can hold up to 12 brands, each with its own slug, for example one per product. The default brand cannot be deleted; make another brand the default first.
Manage brands in the dashboard
Open Templates and choose the Brands tab. A brand page has four sections:
- Details: the name and slug, and whether it is the default.
- Theme: a Form for colors, fonts, and corners, and a CSS tab over the same text. The form is locked while the CSS has errors.
- Logo and icon: the light and dark logos and the icon.
- Footer: company name, postal address, and social links.
The font picker in the theme form offers Google fonts or your own WOFF2 files. Samva hosts either
on its own asset origin and writes the @font-face rules into the brand's CSS, so recipients never
load fonts from Google.
Import a brand in a template
A template uses a brand only when its project theme, theme.css, imports it:
@import "./starter.css";
@import "samva:brand";
@theme {
--radius-button: 999px;
}The order is the precedence, lowest first: the starter the project was created from, then the
brand, then your project's own @theme overrides. @import "samva:brand"; names your default
brand; @import "samva:brand/<slug>"; names one brand. A project imports at most one brand. A
project without the import is unbranded. An @import of anything other than a project .css file
or samva:brand fails the check.
Creating a template from a starter in the dashboard offers a Use my brand checkbox, which writes the import line for you.
Utilities read the brand's theme variables like any other: bg-brand, text-brand-foreground,
font-heading, rounded-button. Starters use these names, so a brand restyles every starter:
| Theme variable | Used for |
|---|---|
--color-brand | The primary color: buttons and the main call to action. |
--color-brand-foreground | Text on the primary color. |
--color-accent | Eyebrows, labels, links, and highlights. |
--color-surface | The content card. |
--font-heading | Headings. |
--font-body | Body text. |
--radius-button | Button corners. |
--radius-card | The content card's corners. |
When a brand sets --color-brand and leaves out --color-brand-foreground, the foreground is black
or white, whichever contrasts more with the brand color.
Render the logo and footer
samva:brand also exports two components bound to the brand the project imports:
/** @jsxImportSource @samva/markup/email */
import { Schema } from "effect";
import { Email, Section } from "@samva/markup/email/components";
import { defineEmail } from "@samva/markup/template";
import { BrandFooter, BrandLogo } from "samva:brand";
export default defineEmail({
id: "welcome",
schema: Schema.toStandardJSONSchemaV1(Schema.Struct({ firstName: Schema.String })),
fixtures: { basic: { firstName: "Ada" } },
render: (input) => ({
subject: `Welcome, ${input.firstName}`,
body: (
<Email>
<Section>
<BrandLogo width={120} align="left" />
<h1 className="font-heading text-brand">Welcome, {input.firstName}</h1>
</Section>
<BrandFooter unsubscribeLabel="Unsubscribe" />
</Email>
),
}),
});<BrandLogo />renders the light logo and swaps to the dark logo in clients that support dark mode. It renders nothing when the brand has no logo.altdefaults to the company name.<BrandFooter />renders the company name, postal address, social links, and an unsubscribe link. The unsubscribe row appears only when the send has an unsubscribe group, and Samva fills its link at send time.
For tsc, add "types": ["@samva/markup/samva-brand"] to the project's tsconfig.json.
Write a brand theme
A brand's CSS holds only theme variables and fonts:
@font-face {
font-family: "Acme Sans";
src: url("https://fonts.example.com/acme-sans-400.woff2") format("woff2");
font-weight: 400;
}
@theme {
--color-brand: #4f46e5;
--color-accent: #0ea5e9;
--font-heading: "Acme Sans", Helvetica, Arial, sans-serif;
--radius-button: 8px;
}
@media (prefers-color-scheme: dark) {
@theme {
--color-brand: #818cf8;
}
}@themeblocks set theme variables in Tailwind's namespaces:--color-*,--font-*,--text-*,--leading-*,--tracking-*,--radius-*,--spacing,--container-*, and--shadow-*.- One dark-mode block,
@media (prefers-color-scheme: dark) { @theme { ... } }, sets colors only. Email inlines styles when it is built, so each dark color becomes a-darkvariable, and a template reads it with adark:utility:bg-brand dark:bg-brand-dark. @font-facerules take an https WOFF2src.
Anything else, such as a selector rule, another at-rule, or a relative font path, is rejected with
each finding located in the CSS. A font stack should end in sans-serif, serif, or monospace,
because Gmail and classic Outlook do not load webfonts. A font file committed in the template
project instead belongs in theme.css; see
Images and fonts in a project.
Publish and republish
Each build compiles against the brand as it is at that moment, and a publication keeps a snapshot of it: theme, logos, footer, and digest. Editing a brand never changes what an existing publication sends. Republish to send the edited brand.
In the dashboard, a template whose publication was built against an older version of its brand
shows Brand updated since publish. Open it for a preview of the difference and a Republish
button. On the brand page, Republish all using the brand republishes every such template and
lists any that failed. From the CLI, samva templates publish republishes the same commit against the
current brand; with an unchanged brand it returns the existing receipt.
Domains and the appended footer
Each domain uses a brand, the default brand unless you choose another under Uses brand on the
domain page or with brandSlug in
Update a domain's send-settings config. The
domain's brand supplies only the footer Samva appends to a message whose template does not render
<BrandFooter />. It never restyles a template. A template that renders <BrandFooter /> signs
off with the brand it was published with, even when that differs from the domain's brand, and the
dashboard points out the difference without failing any send.
Campaigns
Every campaign signs off with a brand footer that includes a postal address and an unsubscribe link:
- The appended footer is on for campaigns. Turning it off is allowed only when the campaign's
template renders
<BrandFooter />; otherwise scheduling and sending fail withCampaignFooterRequiredError. - The brand that signs the campaign off must have a postal address, or scheduling and sending fail
with
BrandAddressRequiredError.
Transactional sends never fail on either rule.
Work with brands from code
The brands API lists, creates, reads, updates, and deletes
brands under /v1/brands and /v1/brands/{slug}, and makes one the default. An update replaces
each section it includes (css, assets, or footer) and leaves the others unchanged.
import { createClient } from "samva";
const samva = createClient({ apiKey: process.env.SAMVA_API_KEY! });
const brand = await samva.brands.get({ slug: "acme" });
console.log(brand.digest);The CLI pulls and pushes brands; see Pull and push a brand:
samva brands list
samva brands get acme --json
samva brands pull acme
samva brands push brand.css --brand acmeLocal previews and samva templates check resolve the imported brand live, using SAMVA_API_KEY
or your samva login session. Offline, they use the snapshot samva brands pull wrote to
.samva/brands/<slug>.json and warn that it may be out of date. With neither, the check fails
with brand-unavailable. Keep .samva in .gitignore.
The hosted MCP server offers brands_list, brands_get, and brands_update. The template editor's
assistant reads the brand a project imports and never edits it.
Related documentation
Authoring in TSX
Create an email definition with a portable input schema and named fixtures, then preview, check, and publish its exact source.
Responsive and dark styles
Author responsive and dark email styles while keeping baseline content usable and reviewing compatibility findings for target clients.