Flow · 11 steps
Design your own emails
Design the emails your customers and suppliers receive — invoices, quotes, order confirmations and purchase orders — in react-email's own components, or start from one of Manifold's.
A template is a small TSX module: a subject, an optional inbox preview, and the email itself, a function of the kind's data (the invoice as issued, the customer, your shop). Start by choosing a style — one look for every kind — then make any kind your own. It runs in a sandbox, so it can only shape the email, and every save is checked against sample data first and refused with the line that went wrong. Each save is a new version; choose which template a kind sends, and send yourself a test to see it arrive.
Services involved
A filled dot is a read; a ring is a call that changes something.
- Notifications:
https://notifications.getmanifold.io
Every call carries Authorization: Bearer $MANIFOLD_TOKEN unless its step says otherwise
(getting a token). Run a flow in your sandbox, not your live
organization: see Before you start.
1 Name the sender
Tests, like every message, go out under the organization's sender: its name and accounts email.
PUT /settings/sender Notifications
{
"senderName": "Ridgeline Outdoor",
"accountsEmail": "accounts@ridgeline-outdoor.example"
}What the answer holds: the operation's example.
Records notifications.sender-saved.
2 Read the catalogue
Each kind with the data it renders and a sample of it, Manifold's starters with their whole source, and the declarations of @manifold/email — what an editor completes and an agent reads first.
GET /email-templates/catalog Notifications
What the answer holds: the operation's example.
3 Choose a style
One look for every kind at once — classic, bold or minimal, or custom: your own layout (a template of kind layout) drawn around each kind's content. Every kind without a template of its own renders that style's starter from now.
PUT /email-templates/style Notifications
{
"style": "bold"
}What the answer holds: the operation's example.
Records notifications.template-style-chosen.
4 Preview a draft
Rendered against the kind's sample and kept nowhere: the editor's live preview.
POST /email-templates/render Notifications
{
"kind": "invoice",
"source": "import { Button, Container, Heading, Text, date, money } from \"@manifold/email\";\nexport const subject = (data) => `Invoice ${data.invoice.number} from ${data.shop.name}`;\nexport const preview = (data) => `${money(data.invoice.totals.totalCents, data.invoice.currency)} due`;\nexport default function Invoice(data) {\n return (\n <Container style={{ padding: \"32px\", fontFamily: \"Helvetica, Arial, sans-serif\" }}>\n <Heading style={{ color: \"#0f5132\" }}>Thanks, {data.customer?.firstName ?? \"there\"}</Heading>\n <Text>Invoice {data.invoice.number} comes to {money(data.invoice.totals.totalCents, data.invoice.currency)}{data.invoice.dueOn ? `, due ${date(data.invoice.dueOn, \"long\")}` : \"\"}.</Text>\n <Button href=\"https://ridgeline-outdoor.example/pay\" style={{ backgroundColor: \"#0f5132\", color: \"#ffffff\", padding: \"12px 20px\", borderRadius: \"999px\" }}>Pay now</Button>\n </Container>\n );\n}\n"
}What the answer holds: the operation's example.
Records nothing.
5 Save it
Checked against the sample first; kept as version 1 with its whole source.
PUT /email-templates/etp_01a15a02-7c41-7a6e-9d10-3f6c2b8e4a12 Notifications
{
"kind": "invoice",
"name": "Invoice — our colours",
"source": "import { Button, Container, Heading, Text, date, money } from \"@manifold/email\";\nexport const subject = (data) => `Invoice ${data.invoice.number} from ${data.shop.name}`;\nexport const preview = (data) => `${money(data.invoice.totals.totalCents, data.invoice.currency)} due`;\nexport default function Invoice(data) {\n return (\n <Container style={{ padding: \"32px\", fontFamily: \"Helvetica, Arial, sans-serif\" }}>\n <Heading style={{ color: \"#0f5132\" }}>Thanks, {data.customer?.firstName ?? \"there\"}</Heading>\n <Text>Invoice {data.invoice.number} comes to {money(data.invoice.totals.totalCents, data.invoice.currency)}{data.invoice.dueOn ? `, due ${date(data.invoice.dueOn, \"long\")}` : \"\"}.</Text>\n <Button href=\"https://ridgeline-outdoor.example/pay\" style={{ backgroundColor: \"#0f5132\", color: \"#ffffff\", padding: \"12px 20px\", borderRadius: \"999px\" }}>Pay now</Button>\n </Container>\n );\n}\n",
"basedOn": "invoice-classic"
}What the answer holds: the operation's example.
Records notifications.template-saved.
6 Save it again
The same content is the template as it stands: nothing appended.
PUT /email-templates/etp_01a15a02-7c41-7a6e-9d10-3f6c2b8e4a12 Notifications
{
"kind": "invoice",
"name": "Invoice — our colours",
"source": "import { Button, Container, Heading, Text, date, money } from \"@manifold/email\";\nexport const subject = (data) => `Invoice ${data.invoice.number} from ${data.shop.name}`;\nexport const preview = (data) => `${money(data.invoice.totals.totalCents, data.invoice.currency)} due`;\nexport default function Invoice(data) {\n return (\n <Container style={{ padding: \"32px\", fontFamily: \"Helvetica, Arial, sans-serif\" }}>\n <Heading style={{ color: \"#0f5132\" }}>Thanks, {data.customer?.firstName ?? \"there\"}</Heading>\n <Text>Invoice {data.invoice.number} comes to {money(data.invoice.totals.totalCents, data.invoice.currency)}{data.invoice.dueOn ? `, due ${date(data.invoice.dueOn, \"long\")}` : \"\"}.</Text>\n <Button href=\"https://ridgeline-outdoor.example/pay\" style={{ backgroundColor: \"#0f5132\", color: \"#ffffff\", padding: \"12px 20px\", borderRadius: \"999px\" }}>Pay now</Button>\n </Container>\n );\n}\n",
"basedOn": "invoice-classic"
}What the answer holds: the operation's example.
Records nothing.
7 Make it what invoices send
From now every invoice email renders this template and names the version it went out with.
PUT /email-templates/kinds/invoice/active Notifications
{
"templateId": "etp_01a15a02-7c41-7a6e-9d10-3f6c2b8e4a12"
}What the answer holds: the operation's example.
Records notifications.template-activated.
8 Send yourself a test
Rendered with the sample and sent to the address you signed in with, subject prefixed [Test].
POST /email-templates/etp_01a15a02-7c41-7a6e-9d10-3f6c2b8e4a12/test Notifications
{
"notificationId": "ntf_01a15889-0b42-7e6d-8a5c-2f1b0e9d8c7c"
}What the answer holds: the operation's example.
Records notifications.requested, notifications.sent.
9 List your templates
Most recently saved first, each with its version and whether its kind sends it.
GET /email-templates Notifications
What the answer holds: the operation's example.
10 Read one
Its latest version, whole: the source, its name and kind, and the starter it came from.
GET /email-templates/etp_01a15a02-7c41-7a6e-9d10-3f6c2b8e4a12 Notifications
What the answer holds: the operation's example.
11 Archive it
Kept with every version but no longer offered; invoices go back to Manifold's default.
POST /email-templates/etp_01a15a02-7c41-7a6e-9d10-3f6c2b8e4a12/archive Notifications
What the answer holds: the operation's example.
Records notifications.template-archived.
What a recorded fact is: Facts and the journal. Why a repeated step changes nothing: Idempotency and retries.