Send your first email in five minutes.
Mailmanny's API lets your code do three things: send transactional email written in React Email, add people to your audiences, and start automations. It's JSON over HTTPS. If you've used Resend or Mailchimp's API, you already know it.
npm install mailmanny @react-email/renderSet up in four steps#
Verify your sending domain
Mailmanny only sends from domains you've proved you own. Add yours in Settings → Domains and add the DNS records it shows you. Verification usually takes a few minutes.
Create an API key
In Settings → API keys, create a key with Full access for now. Copy it right away: Mailmanny shows each key only once. Store it as
MAILMANNY_API_KEYin your server's environment.Install the SDK
The
mailmannypackage has no runtime dependencies. Add@react-email/renderif you want to send React components.npm install mailmanny @react-email/renderSend your first email
Write an email with React Email's components:
emails/welcome.tsxTSX import { Body, Button, Container, Heading, Html, Preview, Text } from "@react-email/components"; export default function WelcomeEmail({ name }: { name: string }) { return ( <Html> <Preview>Your first croissant is on us</Preview> <Body style={{ fontFamily: "Helvetica, Arial, sans-serif" }}> <Container> <Heading>Welcome, {name}!</Heading> <Text>Thanks for joining Manny's Bakery. Show this email for a free croissant.</Text> <Button href="https://mannysbakery.com/menu">See the menu</Button> </Container> </Body> </Html> );}Then send it from any server code: an API route, a server action, a background job.
send-welcome.tsximport { Mailmanny } from "mailmanny";import WelcomeEmail from "./emails/welcome"; const mm = new Mailmanny(process.env.MAILMANNY_API_KEY); const { data, error } = await mm.emails.send({ from: "Manny's Bakery <hello@mannysbakery.com>", to: "sam@example.com", subject: "Welcome to the bakery!", react: <WelcomeEmail name="Sam" />,}); if (error) { console.error(error.name, error.message);} else { console.log("Queued", data.id);}curl -X POST https://www.mailmanny.com/api/v1/emails \ -H "Authorization: Bearer $MAILMANNY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "from": "Manny <hello@mannysbakery.com>", "to": "sam@example.com", "subject": "Welcome to the bakery!", "html": "<p>Your first croissant is on us.</p>" }'import { render } from "@react-email/render";import WelcomeEmail from "./emails/welcome"; const res = await fetch("https://www.mailmanny.com/api/v1/emails", { method: "POST", headers: { Authorization: `Bearer ${process.env.MAILMANNY_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ from: "Manny <hello@mannysbakery.com>", to: "sam@example.com", subject: "Welcome to the bakery!", html: await render(<WelcomeEmail name="Sam" />), }),}); const body = await res.json();if (!res.ok) throw new Error(`${body.name}: ${body.message}`);console.log("Queued", body.id);Mailmanny queues the email and returns its id right away:
Response200 OKJSON { "id": "0199f2a4-5b1c-7d3e-9a2b-4c5d6e7f8a9b", "ids": ["0199f2a4-5b1c-7d3e-9a2b-4c5d6e7f8a9b"]}
Add your first subscriber#
Contacts live in audiences. Adding someone who's already there updates them instead, the same way Mailchimp does it. Get the audience id from mm.audiences.list(), or copy it from the Audience IDs card in Settings → API keys.
const { data, error } = await mm.contacts.create({ audienceId: "0199e9c1-2f3a-7b4c-8d5e-6f7a8b9c0d1e", email: "sam@example.com", firstName: "Sam", tags: ["newsletter"], consentSource: "Footer signup form on mannysbakery.com",});
// Double opt-in audiences: "pending" until they click// the confirmation email.console.log(data?.status);curl -X POST https://www.mailmanny.com/api/v1/audiences/$AUDIENCE_ID/contacts \ -H "Authorization: Bearer $MAILMANNY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "email": "sam@example.com", "first_name": "Sam", "tags": ["newsletter"], "consent_source": "Footer signup form on mannysbakery.com" }'Audiences use double opt-in by default. Mailmanny emails the person a confirmation link, and they become subscribed when they click it. For signup integrations, create an audience key: a key that can only add contacts, to the audiences you pick (see Authentication).
Coming from Resend?#
Change the import and the key. emails.send takes the same fields (from, to, cc, bcc, replyTo, subject, react, html, text, headers, tags, scheduledAt) and returns the same { data, error } result.
- import { Resend } from "resend";- const resend = new Resend(process.env.RESEND_API_KEY);+ import { Mailmanny } from "mailmanny";+ const resend = new Mailmanny(process.env.MAILMANNY_API_KEY);
await resend.emails.send({ from: "Acme <hello@acme.com>", to: "sam@example.com", subject: "Your receipt", react: <ReceiptEmail order={order} />, });Attachments aren't supported: link to the file instead. Everything you send through the API shows up in your workspace's sending stats, and bounces and complaints are suppressed automatically.



