Three lines of curl. You're sending.
A REST API for transactional email. Same infra as the dashboard — same reputation, same deliverability, same verified domains.
Authentication
Every request must carry a bearer token in the Authorization header. Keys start with je_ followed by 64 hex characters, and are shown once at creation — we store only a hash, so keep it somewhere safe. There is no separate test mode: every key sends real mail.
Authorization: Bearer je_3f9a…
Create keys under Settings → API keys in the dashboard, or POST /api-keys. Revoked keys stop working within five seconds. Sending through the API needs a paid plan; accounts in their free trial get 402.
Base URL
https://justemails.app/api/v1
All endpoints below are relative to this base. Every response is JSON. Success responses carry a 2xxstatus and a body with { "data": … }; error responses carry 4xx or 5xx plus a body with { "error": { "code", "message" } }.
Endpoints
Eight endpoints cover send, read, tracking settings and API-key management.
Code examples
Webhooks
Register an HTTPS endpoint under Settings → Webhooks and choose its events. Each delivery is a POST of { "event", "timestamp", "data" } with the header X-JustEmails-Signature: sha256=…, the HMAC-SHA256 of the raw body keyed with the webhook's signing secret. A delivery that does not get a 2xx is retried at 30s, 2m, 10m, 1h and 6h.
email.received
Metadata only — never the body. data.id is the stored email; fetch the body and attachments with GET /emails/{id} (same API key; add ?markRead=false to leave it unread). They are extracted a few seconds after the event fires, so an empty bodyHtml means retry shortly — and is why has_attachments is null in the event. data.to is the address this copy was delivered to (an alias or catch-all address when one was used), data.mailbox where it was stored, and data.folder inbox or spam. Sent only to the webhooks of the account that owns the domain; in an organization, a member's personal mailbox fires nothing.
{
"event": "email.received",
"timestamp": "2026-10-01T09:20:11.502Z",
"data": {
"id": "6c1f0e9a-3b7d-4e52-9a1c-2f8e7d6c5b4a",
"message_id": "CAF=abc123@mail.gmail.com",
"mailbox": "support@yourdomain.com",
"from": "Alice Example <alice@example.com>",
"to": ["help@yourdomain.com"],
"subject": "Order 1042 never arrived",
"received_at": "2026-10-01T09:20:11.497Z",
"size_bytes": 48213,
"has_attachments": null,
"folder": "inbox",
"timestamp": "2026-10-01T09:20:11.497Z"
}
}Open and click tracking
Off by default, and only ever applied to mail sent through this API — never to mail from your mailboxes (webmail, IMAP/SMTP clients, forwarding). Turn it on for every send with PATCH /account/api-settings or in the dashboard, or per send with trackOpens / trackClicks, which override the default either way.
Only the HTML part changes. Opens add a 1×1 image; clicks rewrite each http(s) link to a signed https://justemails.app/t/c/… redirect that records the click and forwards to your link — and only to the link it was signed for. The plain-text part is sent exactly as written. Add data-je-notrack to an <a> to leave it alone. The rewrite happens before DKIM signing.
Each open or click is an opened / clickedevent on the message (the click's detail is the link) and an email.opened / email.clicked webhook carrying the message's id, from, to, subject, tags and metadata, plus urlfor a click. We do not record the reader's IP address or device. Repeats within a minute count once; at most 50 opens and 50 clicks are recorded per message per hour.
Opens are approximate. Apple Mail Privacy Protection loads images on the reader's behalf, so opens are recorded that never happened; Gmail and other image proxies cache the image, so repeat opens are not seen; clients that block images record nothing. Link scanners can register clicks. With several recipients on one message, an open or click cannot be tied to one of them. You are responsible for any notice or consent your recipients' law requires.
Rate limits
Request rates are counted per client IP over the window shown. Sending limits are counted per account, across the dashboard and the API. Exceeding either returns 429 Too Many Requests with a Retry-After header telling you how long to back off, and an error.code naming the limit.
Error codes
Every error response carries a JSON body with error.code (machine-readable) and error.message (human).
140+ tools exposed via MCP.
Every action in the dashboard — domain add, DKIM rotate, alias create, forward rule, invoice fetch — is callable from any MCP-aware AI. Wire JustEmails into Claude, ChatGPT, Cursor, or any client that speaks the protocol.