Send email as Markdown
Write the body of a message in Markdown and the Anypost TypeScript SDK renders it to email-safe HTML and a plain-text alternative for you. You skip the table layouts and inline-style workarounds that hand-written HTML email demands.
Markdown rendering is a feature of the TypeScript SDK only. It runs on
emailmd, which depends on Node 20+ and does not
run in edge or browser runtimes. Every other way to send accepts the
already-rendered html/text you produce however you like.
Why Markdown
HTML email is its own dialect. Layouts are built from nested tables, styles have to be inlined, and every client renders them a little differently. Writing that by hand, or keeping a templating pipeline that emits it, is the tax of sending good-looking mail.
Markdown moves that work to render time. You write prose; emailmd produces a
complete, client-tested HTML document and a matching plain-text part in one
step. The plain-text body is generated automatically, so the message degrades
cleanly where HTML is stripped.
Install
emailmd is an optional peer dependency. Install it alongside the SDK only if
you send Markdown:
npm install anypost emailmdA Markdown send without emailmd installed throws a clear error telling you to
add it. Nothing else in the SDK requires it.
Send Markdown
Pass markdown in place of html and text. The SDK renders it before the
request and sends the result:
import { Anypost } from "anypost";
const anypost = new Anypost("ap_your_api_key");
await anypost.email.send({
from: "Acme <[email protected]>",
to: ["[email protected]"],
subject: "Welcome aboard",
markdown: [
"# Welcome aboard",
"",
"Thanks for signing up. Your workspace is ready.",
"",
"[Open your dashboard](https://app.example.com)",
].join("\n"),
});markdown cannot be combined with html or text; choose one content source.
Everything else on the message — from, to, attachments, tags, headers —
behaves exactly as it does on a normal send. See
Send a single email.
Preheader and frontmatter
A YAML frontmatter block sets the preheader, the preview line shown in the inbox before a message is opened, and carries any custom keys you want to read back:
await anypost.email.send({
from: "[email protected]",
to: ["[email protected]"],
subject: "Your March report",
markdown: [
"---",
"preheader: 12% more opens than February",
"---",
"# Your March report",
"",
"The numbers are in.",
].join("\n"),
});Theme it
Pass render options through markdownOptions to set a brand color, fonts, and
the rest of the theme:
await anypost.email.send({
from: "[email protected]",
to: ["[email protected]"],
subject: "Welcome aboard",
markdown: "# Welcome aboard\n\nGlad you are here.",
markdownOptions: {
theme: { brandColor: "#4f46e5" },
},
});In a batch, set markdownOptions once on defaults to
apply one theme to every entry's Markdown:
await anypost.email.sendBatch({
defaults: { markdownOptions: { theme: { brandColor: "#4f46e5" } } },
emails: [
{ from, to: ["[email protected]"], subject: "Hi A", markdown: "# Hi A" },
{ from, to: ["[email protected]"], subject: "Hi B", markdown: "# Hi B" },
],
});The full theme shape, the wrapper and font options, validation levels, and the
Markdown extensions emailmd supports are covered in the
emailmd docs.
Render once, reuse
To render the same Markdown for many recipients, or to inspect the output
before sending, call renderMarkdown directly. It returns the HTML, the
plain-text alternative, and the extracted frontmatter:
import { renderMarkdown } from "anypost";
const { html, text, meta } = await renderMarkdown("# Hi\n\nOne render, many sends.");
console.log(meta.preheader);
// pass html/text into as many sends as you likeWhere to go next
- Send a single email: the full send request and every field.
- Batch sending: send up to 100 messages in one request.
- emailmd docs: themes, fonts, and the Markdown it renders.