Skip to content

Documentation

Send your first email.

Everything here is the current API. MAILTRUSS_URL is the address of your Mailtruss deployment; MAILTRUSS_API_KEY is a key from the dashboard.

Quickstart

  1. 1Create an account and an organization.
  2. 2Add a sending domain under Domains and publish the five DNS records it shows.
  3. 3Create a key under API keys. It is shown once.
  4. 4Send:
cURL
curl -X POST "$MAILTRUSS_URL/api/v1/emails" \
  -H "Authorization: Bearer $MAILTRUSS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Acme <hello@mail.acme.dev>",
    "to": "ana@fabrikam.com",
    "subject": "Welcome to Acme",
    "html": "<p>Thanks for signing up.</p>"
  }'

The response is { "id": "…" }. Open the email in the dashboard to see its delivery trace, or fetch it with GET /api/v1/emails/:id.

Libraries and AI assistants

Official clients cover every endpoint below. They have no dependencies.

TypeScript / JavaScript
npm install mailtruss

import { MailClient } from "mailtruss";
const mail = new MailClient({ apiKey: process.env.MAILTRUSS_API_KEY! });
await mail.emails.send({ from: "you@yourdomain.com", to: "them@example.com", subject: "Hello", html: "<p>Hi</p>" });
Python
pip install mailtruss

from mailtruss import Mailtruss
m = Mailtruss(api_key="ms_live_...")
m.emails.send(from_="you@yourdomain.com", to="them@example.com", subject="Hello", html="<p>Hi</p>")

To let an AI assistant (Claude, Cursor and other MCP clients) send mail and manage your account, add the MCP server with your API key. Set MAILTRUSS_MCP_READONLY=1 to allow reading only.

MCP configuration
{ "mcpServers": { "mailtruss": { "command": "npx", "args": ["-y", "mailtruss-mcp"], "env": { "MAILTRUSS_API_KEY": "ms_live_..." } } } }

Authentication

Send the key as a bearer token: Authorization: Bearer ms_live_…. Keys are either full access or sending only, which can call only the send endpoints. Keys are stored as a one-way hash and cannot be shown again.

Sending

Fields: from, to, subject, html and/or text, plus optional cc, bcc, reply_to (each up to 50 addresses), headers, tags, attachments (base64 content), scheduled_at, and template ({ "id", "variables" }). The from domain must be verified.

Idempotency

Add an Idempotency-Key header to make a send safe to retry. Repeating a request with the same key and body returns the first response instead of sending again. Reusing a key with a different body returns 409 invalid_idempotent_request.

Header
Idempotency-Key: welcome-user-4812

Scheduling

Set scheduled_at to an ISO 8601 time up to 30 days ahead. Until it starts sending, reschedule with PATCH /api/v1/emails/:id or cancel with POST /api/v1/emails/:id/cancel.

Batches

POST /api/v1/emails/batch takes an array of up to 100 email objects and returns { "data": [{ "id" }, …] }.

Checking what happened

GET /api/v1/emails/:id returns the email with last_event: one of queued, scheduled, sent, delivered, delivery_delayed, bounced, complained, failed and others. The full trace, every recorded event and the diagnosis are in the dashboard. Webhooks can push the same events to your endpoint, signed with your endpoint’s secret.

Domains

POST /api/v1/domains with { "name": "mail.acme.dev" } returns the records to publish: three DKIM CNAMEs, and an MX and SPF TXT record for the return path. Call POST /api/v1/domains/:id/verify to re-check. Each group is reported as pending, verified or failed; DNS changes can take minutes to hours.

Endpoint reference

Sending endpoints work with both key types; everything else needs a full-access key. The same list is available as an OpenAPI 3.1 document you can load into any client generator.

API endpoints
MethodPathDoes
POST/api/v1/emailsSend one email
POST/api/v1/emails/batchSend up to 100 emails
GET/api/v1/emailsList recent emails (limit, after)
GET/api/v1/emails/:idRetrieve an email and its last event
PATCH/api/v1/emails/:idReschedule a scheduled email
POST/api/v1/emails/:id/cancelCancel a scheduled email
GET/api/v1/domainsList domains
POST/api/v1/domainsAdd a domain and get its DNS records
POST/api/v1/domains/:id/verifyRe-check a domain's verification
GET/api/v1/api-keysList API keys
POST/api/v1/api-keysCreate an API key (shown once)
DELETE/api/v1/api-keys/:idRevoke an API key
GET/api/v1/domains/:idRetrieve a domain and its DNS records
DELETE/api/v1/domains/:idDelete a domain
POST/api/v1/contactsCreate or update a contact by email
GET/api/v1/contactsList contacts (q, tag, status, page, limit)
GET/api/v1/contacts/:idRetrieve a contact by id or email
PATCH/api/v1/contacts/:idUpdate a contact
DELETE/api/v1/contacts/:idDelete a contact
GET/api/v1/segmentsList segments
POST/api/v1/segmentsCreate a segment from rules
GET/api/v1/segments/:idRetrieve a segment with its size
DELETE/api/v1/segments/:idDelete a segment
GET/api/v1/topicsList topics
POST/api/v1/topicsCreate a topic
GET/api/v1/templatesList templates
POST/api/v1/templatesCreate a template (optionally publish)
GET/api/v1/templates/:idRetrieve a template
PATCH/api/v1/templates/:idSave a new, unpublished version
POST/api/v1/templates/:id/publishPublish a version
DELETE/api/v1/templates/:idDelete a template
GET/api/v1/broadcastsList broadcasts
POST/api/v1/broadcastsCreate a draft broadcast
GET/api/v1/broadcasts/:idRetrieve a broadcast with delivery stats
POST/api/v1/broadcasts/:id/sendSend now or schedule
POST/api/v1/broadcasts/:id/cancelCancel a scheduled or sending broadcast
DELETE/api/v1/broadcasts/:idDelete a draft
GET/api/v1/suppressionsList suppressed addresses
POST/api/v1/suppressionsSuppress an address
DELETE/api/v1/suppressions/:idRemove a bounce or manual entry
GET/api/v1/webhooksList webhook endpoints
POST/api/v1/webhooksCreate an endpoint (signing secret shown once)
PATCH/api/v1/webhooks/:idUpdate or pause an endpoint
POST/api/v1/webhooks/:id/rotate-secretRotate the signing secret (old one works 24 hours)
DELETE/api/v1/webhooks/:idDelete an endpoint
GET/api/v1/logsList API request logs

Errors

Every error has the same shape, and every response has an x-request-id header you can search in API logs.

422
{ "name": "validation_error", "message": "subject: Missing `subject` field.", "statusCode": 422 }
403invalid_api_key
The key does not exist, was revoked, or has expired. Create a new one under API keys.
401missing_api_key
Send the key as Authorization: Bearer <key>.
401restricted_api_key
This key is sending-only. Use a full-access key for this endpoint.
403domain_not_verified
The from domain is not verified. Open Domains, publish the DNS records and re-check.
422validation_error
Fix the field named in the message. The request was rejected before processing; no quota was used.
429rate_limit_exceeded
Back off and retry after the Retry-After header. Use /emails/batch to send many messages in one request.
429daily_quota_exceeded
The daily cap was reached. It resets at 00:00 UTC.
429monthly_quota_exceeded
The plan's monthly limit was reached.
409invalid_idempotent_request
That Idempotency-Key was already used with a different body. Use a new key for a new request.
409concurrent_idempotent_requests
Another request with this key is still processing. Wait a moment and retry with the same key.
422invalid_scheduled_at
Use an ISO 8601 date-time in the future, at most 30 days ahead.
404not_found
No such resource in this organization.
403account_suspended
This organization is suspended. Contact support.