Skip to content

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.

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
POST /v0/inboxes/shop-helper@simail.email/messages/send
Authorization: Bearer $SIMAIL_API_KEY
Idempotency-Key: order-1042-shipped
Content-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.

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-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.

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.

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.

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, approval or block for 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.

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, 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.