01 · MailMarco API
Getting started
Five requests from nothing to a delivered email. Everything on this page is copy-pasteable against the live API.
What the API covers
MailMarco is one API for the whole lifecycle of a message. The surface splits into six areas, each documented on its own page:
- Sending —
/v1/emails, single, batch and scheduled, with idempotency, attachments and templates. - Domains —
/v1/domains, DKIM keypair generation and DNS verification. - Events —
/v1/webhooks, signed HTTP callbacks for every state change. - Deliverability — suppressions, bounces, complaints, plan limits and warm-up caps.
- Marketing — contacts, topics, segments and broadcasts.
- Inbound — MX-hosted receiving, routing rules and message retrieval.
Base URL and versioning
Every route lives under a single origin and is prefixed with the API version. There is one version today.
https://api.mailmarco.com/v1Requests and responses are JSON (content-type: application/json) unless a route explicitly says otherwise — the contact export returns CSV, the raw-message endpoint returns message/rfc822, and the tracking pixel returns a GIF. Timestamps are ISO-8601 with an offset. Identifiers are UUIDs.
1. Create an account
Signing up creates a user and their first organization in one call. The organization is the tenant boundary: every key, domain, contact and message belongs to exactly one organization.
curl -X POST https://api.mailmarco.com/v1/auth/signup \
-H "content-type: application/json" \
-d '{
"email": "[email protected]",
"password": "a-long-password",
"organizationName": "Example Inc"
}'organizationName is optional — omit it and the name and slug are derived from the email local-part. The password must be at least 8 characters. Sign-up is rate limited to 5 requests per hour per IP.
Then log in to get a session access token:
curl -X POST https://api.mailmarco.com/v1/auth/login \
-H "content-type: application/json" \
-d '{"email":"[email protected]","password":"a-long-password"}'
# => {"accessToken":"eyJhbGciOi...","refreshToken":"..."}2. Create an API key
Key management is part of the dashboard surface, so it authenticates with the session access token from the previous step — not with an API key.
curl -X POST https://api.mailmarco.com/v1/api-keys \
-H "authorization: Bearer $MAILMARCO_ACCESS_TOKEN" \
-H "content-type: application/json" \
-d '{"name":"production","scopes":["emails:send"]}'{
"id": "0f0a1a1e-6f6f-4f3a-9c2e-6b6a5a1d7c11",
"name": "production",
"prefix": "9f1c3d5b7e9a1c3d",
"scopes": ["emails:send"],
"token": "mf_live_9f1c3d5b7e9a1c3d.8kQ2h9Rt7vXc1mB4nZ0pL6sW",
"lastUsedAt": null,
"revokedAt": null,
"createdAt": "2026-07-29T09:14:02.113Z"
}3. Add and verify a sending domain
You can only send from a domain your organization owns and has verified. Adding one mints a fresh DKIM keypair and returns the exact records to publish.
curl -X POST https://api.mailmarco.com/v1/domains \
-H "authorization: Bearer $MAILMARCO_ACCESS_TOKEN" \
-H "content-type: application/json" \
-d '{"domain":"mail.example.com"}'{
"id": "3c2b1a09-8d7e-4c5b-a6f2-1e0d9c8b7a65",
"domain": "mail.example.com",
"status": "pending",
"region": "eu",
"verifiedAt": null,
"createdAt": "2026-07-29T09:16:41.882Z",
"records": [
{
"type": "SPF",
"host": "mail.example.com",
"value": "v=spf1 include:spf.mailmarco.com ~all",
"ttl": 3600,
"verified": false
},
{
"type": "DKIM",
"host": "mm20260729a1b2c3._domainkey.mail.example.com",
"value": "v=DKIM1; k=rsa; p=MIIBIjANBgkq...",
"ttl": 3600,
"verified": false
}
]
}Publish all five records at your DNS provider, then ask MailMarco to re-check. The selector in the DKIM host is unique to your domain — copy it from the response, never from this page.
curl -X POST https://api.mailmarco.com/v1/domains/$DOMAIN_ID/verify \
-H "authorization: Bearer $MAILMARCO_ACCESS_TOKEN"The domain reaches verified when every required record resolves. Full detail, including what each record does and why the return-path record is a CNAME, is on the Domains page.
4. Send your first email
Sending uses the API key, not the session token. A successful send answers 202 Accepted — the message is persisted and queued, not yet delivered.
curl -X POST https://api.mailmarco.com/v1/emails \
-H "authorization: Bearer $MAILMARCO_API_KEY" \
-H "content-type: application/json" \
-H "idempotency-key: welcome-user-42" \
-d '{
"from": "[email protected]",
"to": "[email protected]",
"subject": "Welcome aboard",
"html": "<h1>Hello</h1><p>Thanks for signing up.</p>",
"text": "Hello. Thanks for signing up."
}'import { MailMarco } from "@mailmarco/sdk-node";
const mm = new MailMarco({
apiKey: process.env.MAILMARCO_API_KEY!,
baseUrl: "https://api.mailmarco.com",
});
const sent = await mm.emails.send(
{
from: "[email protected]",
to: "[email protected]",
subject: "Welcome aboard",
html: "<h1>Hello</h1><p>Thanks for signing up.</p>",
text: "Hello. Thanks for signing up.",
},
{ idempotencyKey: "welcome-user-42" },
);
console.log(sent.id, sent.status); // "…", "queued"{
"id": "b1d2e3f4-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"status": "queued"
}5. Look up the message
Fetching a message returns its recipients and the full event timeline — the same events that fire your webhooks.
curl https://api.mailmarco.com/v1/emails/$MESSAGE_ID \
-H "authorization: Bearer $MAILMARCO_API_KEY"{
"id": "b1d2e3f4-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
"status": "queued",
"from": "[email protected]",
"subject": "Welcome aboard",
"sandbox": false,
"createdAt": "2026-07-29T09:22:10.004Z",
"recipients": [
{ "type": "to", "address": "[email protected]", "status": "queued" }
],
"events": [
{ "type": "queued", "occurredAt": "2026-07-29T09:22:10.004Z", "providerResponse": null }
]
}Next steps
| Do this next | Why |
|---|---|
| Subscribe to webhooks | 202 means accepted, not delivered. Delivery, bounce and complaint outcomes only arrive as events. |
| Read the deliverability rules | Suppressions, plan limits (402) and warm-up caps (429) all reject sends before they leave the API. |
| Learn the error envelope | One shape for every failure, with a stable `error` code you can branch on. |
| Install the Node SDK | Typed helpers over the same routes, plus a machine-readable OpenAPI document. |
Environment variables used on this site
Every sample assumes these are exported:
export MAILMARCO_API_KEY="mf_live_…" # runtime routes: /v1/emails, /v1/webhooks, …
export MAILMARCO_ACCESS_TOKEN="eyJhbGciOi…" # management routes: /v1/domains, /v1/api-keys, …