Mailgentic

Sending email

The relay accepts mail over REST (POST /v1/messages) or SMTP submission. Both paths run the same pipeline: tenant quotas and rates, suppression list, Guardian checks, DKIM signing, queueing, retries, and events.

POST /v1/messages

curl -X POST "$API/v1/messages" \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-8842-shipped" \
  -d '{
    "tenant_id": "TENANT_ID",
    "from": "Shop <orders@shop.example.com>",
    "to": ["customer@example.net"],
    "cc": [],
    "bcc": [],
    "reply_to": "support@shop.example.com",
    "subject": "Your order has shipped",
    "text": "Your order 8842 is on its way.",
    "html": "<p>Your order <b>8842</b> is on its way.</p>",
    "headers": {"X-Campaign": "post-purchase"},
    "attachments": [{
      "filename": "invoice.pdf",
      "content_type": "application/pdf",
      "content": "<base64>"
    }],
    "tags": ["transactional", "shipping"],
    "metadata": {"order_id": "8842"}
  }'
Field Notes
tenant_id Required with an account-wide key; implied by a tenant-bound key
from Must be on a domain registered to the tenant and verified (the shared agents.mailgentic.ai domain can only be used by sending from an inbox, never as a free-form from)
to, cc, bcc Arrays of addresses; total recipients capped by the tenant’s max_recipients_per_message
text / html At least one required
attachments Base64; up to 25 MiB total after decoding. Optional content_id and inline for embedded images
tags Free-form strings; filterable in events, usable as a pause scope
metadata Arbitrary JSON echoed in events and webhooks
idempotency_key Alternative to the Idempotency-Key header

Response

{ "message_id": "MESSAGE_ID", "queued": 1, "held": 0, "suppressed": 0, "duplicate": false }

202 Accepted is returned as soon as the message is durably queued.

Idempotency

Any client that retries should set Idempotency-Key. Keys are scoped to the tenant and remembered long enough to cover realistic retry windows. A replay returns the original identity rather than sending a second copy.

Delivery status

GET /v1/messages/{id}

Returns { "message": {…}, "deliveries": [...] } — one delivery record per recipient:

{
  "recipient": "customer@example.net",
  "status": "delivered",
  "attempts": 1,
  "smtp_response": "250 2.0.0 OK",
  "bounce_class": null,
  "next_attempt_at": null,
  "expires_at": "2026-10-07T10:00:00Z",
  "delivered_at": "2026-10-04T10:00:03Z"
}

GET /v1/messages

Newest first. Filters: tenant_id, recipient, from, status, since, until, before (cursor), limit (default 50, max 200).

GET /v1/events

The account’s event stream, newest first. Filters: type, tenant_id, message_id, recipient, before_id, limit. Each event has an increasing numeric id, type, message_id, delivery_id, recipient, data and created_at.

Event Meaning
accepted Submission accepted and queued
held / released Parked by a pause / re-queued after release
delivered Remote server accepted the message
deferred Temporary failure; will retry until expiry
bounced Permanent failure (data.bounce_class tells you why)
blocked Refused by a receiving server’s policy
complained Recipient reported spam (feedback loop)
suppressed Recipient skipped because it is on the suppression list
expired Retries exhausted
cancelled Purged from a held queue
unsubscribed Recipient used list-unsubscribe
suspended / resumed A pause was created or lifted on a scope covering this mail
anomaly_detected The Guardian flagged a pattern (see Shield and Guardian)
auth_failed / rejected Submission refused (bad credential, suspended scope, policy)

Events are also delivered by webhook.

Suppression list

Hard bounces and complaints add the recipient to the tenant’s suppression list automatically; later sends to that address are skipped and emit suppressed.

Method Path Scope Purpose
GET /v1/suppressions read Search the list
POST /v1/suppressions feedback Add an address manually
DELETE /v1/suppressions/{id} admin Remove an entry
POST /v1/complaints feedback Record a complaint you received out of band

Sending from an inbox

Mail composed from an agent inbox (POST /v1/inboxes/{id}/messages, replies, forwards, drafts) goes through this same pipeline and additionally through the inbox’s Agent Shield policy. See Inboxes.

SMTP submission

Same pipeline, different door. See IMAP and SMTP for hosts, ports and credential rules.