Sending
Agents never hold a mail-sending credential. Every outbound message is submitted to SiMail’s release service, a separate service that is the only component able to send mail. It checks the message, applies your organization’s policy, waits for approval if the policy requires it, and runs a final check immediately before the message leaves.
SiMail is for expected, transactional mail. Cold outreach and bulk mail are not allowed; see the Acceptable Use Policy.
Endpoints
Section titled “Endpoints”| Method and path | Permission |
|---|---|
POST /v0/inboxes/{inbox_id}/messages/send |
message_send |
POST /v0/inboxes/{inbox_id}/messages/{message_id}/reply |
message_send |
POST /v0/inboxes/{inbox_id}/messages/{message_id}/reply-all |
message_send |
POST /v0/inboxes/{inbox_id}/messages/{message_id}/forward |
message_send |
GET, POST /v0/inboxes/{inbox_id}/drafts; GET, PATCH, DELETE …/drafts/{draft_id} |
message_read, draft_write |
POST /v0/inboxes/{inbox_id}/drafts/{draft_id}/attachments |
draft_write |
POST /v0/inboxes/{inbox_id}/drafts/{draft_id}/send |
message_send |
GET /v0/sends/{send_id} |
message_read |
DELETE /v0/sends/{send_id} (cancel) |
message_send |
GET /v0/approvals, GET /v0/approvals/{approval_id} |
approval_read |
Request
Section titled “Request”POST /v0/inboxes/shop-helper@simail.email/messages/sendAuthorization: Bearer $SIMAIL_API_KEYIdempotency-Key: order-1042-shippedContent-Type: application/json
{ "to": ["ada@example.com"], "subject": "Your order shipped", "text": "Hi Ada, your order #1042 shipped today.", "labels": ["orders"]}| Field | Notes |
|---|---|
to, cc, bcc |
up to 50 recipients in total; bcc only if your policy allows it |
subject |
|
text, html |
at least one; always send text |
attachments |
[{ "filename", "content_type", "content" }] with base64 content, or { "draft_attachment_id" }; at most 32 |
labels |
labels for the sent copy |
send_at |
ISO 8601 time up to 30 days ahead; the message is sent within about 2 minutes of that time |
reply_to |
ignored: SiMail sets Reply-To itself so replies thread correctly |
headers |
rejected, except X-Simail-Client-Ref |
track_opens |
ignored: SiMail does not track opens or clicks |
Header fields with CR, LF, NUL or other control characters are rejected with 422 invalid_header.
Replies
Section titled “Replies”For reply, SiMail takes the recipient from the original message’s From address (never from
its Reply-To). reply-all adds the original To and Cc, minus your own address. Subjects get Re: or
Fwd:, and threading headers are set for you. You may pass expected_recipients; if they differ from
the recipients SiMail derived, the send is blocked, which protects against a reply silently turning
into a broadcast. Forwarded mail goes to new recipients, so forwarding counts as first contact.
The whole outbound message, including headers, body, attachments and encoding overhead, must be at
most 5 MiB (about 3.5 MiB of raw attachments), with at most 32 attachments. Larger messages
return 413 message_too_large with limit_bytes and estimated_bytes. Request bodies are limited to
5 MiB for sends with inline attachments and 1 MiB otherwise.
Idempotency
Section titled “Idempotency”Idempotency-Key is required on every send (send, reply, reply-all, forward, draft
send). Keys are scoped to your organization and your key. The same key with the same body returns the
original result; the same key with a different body returns 409 idempotency_conflict. Retrying a
send after a timeout with the same key never sends twice.
Response
Section titled “Response”202 Accepted:
{ "send_id": "out_…", "message_id": "msg_…", "thread_id": "thr_…", "status": "pending_approval", "flags": ["first_contact"] }status |
Meaning |
|---|---|
sent |
handed to the mail network |
sending |
being sent now |
scheduled |
waiting for send_at |
pending_approval |
waiting for a human (see below) |
blocked |
refused; returned as 422 send_blocked with reasons |
Later states, visible at GET /v0/sends/{send_id}: approved, rejected, expired, cancelled,
failed, and outcome_unknown (the send may or may not have gone out; SiMail never resends it
automatically and reconciles it when a delivery event arrives).
Cancel with DELETE /v0/sends/{send_id} while a message is scheduled, pending_approval or
approved. Once it is sending or final, cancel returns 409 conflict with reason: "already_sending"
or "already_final". Deleting a submitted draft cancels it first.
Pre-send checks
Section titled “Pre-send checks”Blocking reasons (reasons): sender_mismatch, empty_body, placeholder (for example {{,
[NAME], TODO, lorem ipsum), too_many_recipients, body_too_large, attachment_too_large,
attachment_not_allowed, invalid_address, invalid_header, suppressed (the address bounced hard
or complained), blocked_recipient, duplicate, loop_auto_reply, loop_thread, loop_peer,
card_number, credential, expected_recipients_mismatch, thread_locked, first_contact_blocked,
message_too_large, principal_revoked, policy_changed, daily_limit_at_send, platform_hard_cap.
Risk flags (flags, shown to approvers): first_contact, punycode, lookalike_domain,
cross_thread_echo (the message reuses content from other threads you read), has_links,
has_attachments, bcc, credential_like, large_recipient_set, new_recipient_domain,
recipient_unverified.
Duplicates and loops. An identical message (same sender, recipients, subject and body) inside the
de-duplication window returns 409 duplicate_send. Replies to auto-replies, bounces or mail from other
SiMail agents are blocked, as are threads and peers that exceed the exchange limits, so two agents
cannot mail each other forever.
Final check. Right before a scheduled, approved or delayed message is sent, SiMail re-checks the current state: platform or organization pause, revoked keys, deleted or paused inboxes, thread locks, suppressions and block lists, the current policy and today’s limits. A message that no longer passes is held back or blocked; it is never sent on stale approval.
Policy and approvals
Section titled “Policy and approvals”Policies are set by humans in the console at the organization, pod, inbox or key level; each level can only be stricter than the one above. The main settings:
approval.mode:none,first_contact,risky(any flag),first_contact_and_risky,all.first_contact:allow,approvalorblockfor recipients who are not contacts of the inbox.- Daily limits per organization, inbox, key and recipient, plus a per-thread hourly limit.
- Whether
bcc, outbound attachments and links are allowed.
When approval is required, approvers get a card in the console (and, if connected, in Telegram or
Slack, or by email) showing the full recipient list, subject, the start of the body, attachments and
flags. Approval is bound to the exact content: if the message changes, the approval no longer
applies. Approvals expire after 24 hours by default. Agents can read approval status
(GET /v0/approvals) but can never approve.
Branding and headers
Section titled “Branding and headers”Outbound mail is signed simail.ai: a one-line footer — Sent by an AI agent via simail.ai, and
“ via SiMail” after the display name. Messages carry Auto-Submitted headers so other systems know
they are automated. SiMail adds no tracking pixels and no remote images.
Delivery events and suppression
Section titled “Delivery events and suppression”Delivery, bounce, complaint and rejection events come from the sending network and are reported as
message.delivered, message.bounced, message.complained and message.rejected. Hard bounces and
complaints add the address to your suppression list. If an organization’s 7-day hard-bounce rate
reaches 2% or its complaint rate reaches 0.1% (after at least 50 messages), sending is paused for that
organization (403 account_suspended, receiving continues) until a human resumes it in the console.