Guides
Approvals & send policy
How send policy is layered and merged, when a human must approve a message, what approvers see, and what agents can observe.
docs.simail.ai/approvals
Every outbound message is checked against your organization’s send policy by the release service. The policy decides whether a message is sent at once, held for a human’s approval, or blocked. Humans edit policy in the console (with re-verification); agents can read their effect but never change it.
Layers: each one can only be stricter
Section titled “Layers: each one can only be stricter”Policy is set at five levels and merged from the top down:
platform → organization → pod → inbox → key
A lower level can make the result stricter, never looser. “Stricter” is defined per field, so the merge is predictable:
| Field | Stricter means |
|---|---|
limits.*, approval.ttl_minutes, attachments.max_total_bytes, injection.hold_threshold, loop_guard.max_exchanges_*, inbound.wake.* | the smaller number |
dedupe.window_minutes, loop_guard.window_hours | the larger number |
recipients.allow_bcc, attachments.allow_outbound, links.allow | false wins |
content.block_*, recipients.block_punycode, loop_guard.block_reply_to_auto_submitted, llm_injection_scoring, branding.footer | true wins |
approval.mode | none < first_contact < risky < first_contact_and_risky < all |
first_contact | allow < approval < block |
approval.approvers | set by the organization; lower levels can only remove people |
The policy document
Section titled “The policy document”{ "approval": { "mode": "first_contact_and_risky", "channels": ["console", "telegram", "slack", "email_reply"], "ttl_minutes": 1440, "approvers": ["usr_…"] }, "first_contact": "approval", "limits": { "daily_recipients": 100, "inbox_daily_recipients": 200, "key_daily_recipients": 200, "per_thread_per_hour": 10, "per_recipient_per_day": 20, "max_recipients_per_message": 50 }, "dedupe": { "window_minutes": 1440 }, "loop_guard": { "block_reply_to_auto_submitted": true, "max_exchanges_per_thread_per_day": 20, "max_exchanges_per_peer_per_day": 40, "window_hours": 24 }, "content": { "block_credentials": false, "block_card_numbers": true, "block_empty": true, "block_placeholders": true }, "recipients": { "allow_bcc": false, "block_punycode": false }, "attachments": { "allow_outbound": true, "max_total_bytes": 3670016 }, "links": { "allow": true }, "branding": { "footer": true, "display_name_suffix": true }, "t0": { "stranger_thread": "approval", "auto_per_thread_per_day": 3, "thread_token_ttl_days": 30 }, "inbound": { "wake": { "stranger_daily": 50, "per_sender_hourly": 5 } }, "injection": { "hold_threshold": 0.7 }, "llm_injection_scoring": false}These are the defaults for a new organization. The least strict approval mode an organization can
choose is first_contact_and_risky; none is not available.
When approval is required
Section titled “When approval is required”approval.mode | A human approves |
|---|---|
first_contact | messages to someone who is not yet a contact of the inbox |
risky | messages with any risk flag |
first_contact_and_risky | either of the above (default) |
all | every message |
Independently of the mode:
first_contact: blockrefuses first-contact mail outright (first_contact_blocked).- Threads started by a stranger need approval for every reply (
t0.stranger_thread), unless a human has promoted the sender to a contact. - At most
t0.auto_per_thread_per_daymessages per thread per day are sent without approval; the rest wait for a human. - A message that reuses content from other threads your agent read (
cross_thread_echo) needs approval. This is the classic shape of a prompt-injection exfiltration. - Forwarding to new recipients counts as first contact.
Risk flags shown to approvers: first_contact, punycode, lookalike_domain,
cross_thread_echo, has_links, has_attachments, bcc, credential_like, large_recipient_set,
new_recipient_domain, recipient_unverified.
Contacts. Someone becomes a contact of an inbox when the inbox wrote to them first and they replied, or when a human promotes them in the console.
What approvers see and decide
Section titled “What approvers see and decide”An approval card shows the sender, every envelope recipient as the release service will send it, the subject, the first 2,000 characters of the body, attachment names and sizes, the risk flags, the key that submitted it and a link to the thread in the console.
Approvers can decide in:
- the console (approvers, owners and admins; re-verification within 5 minutes),
- Telegram or Slack, once a human has connected them in the console,
- email: reply
APPROVEorREJECTon the first line to the approval request (only from an approver’s verified address, with an aligned DKIM signature).
An approval is bound to the exact content. If the message changes after it was requested, the approval
no longer applies. Each approval can be decided once. Undecided approvals expire after
approval.ttl_minutes (24 hours by default), and the message is not sent.
What agents see
Section titled “What agents see”Agents never approve. They can follow the outcome:
- the send response says
status: "pending_approval", withflags; GET /v0/sends/{send_id}moves toapproved(thensending,sent),rejected,expiredorcancelled(Sends);GET /v0/approvalsandGET /v0/approvals/{approval_id}return metadata only (Approvals API);approval.requestedandapproval.decidedevents report changes.
An agent waiting for approval should not resend the message with a new idempotency key; that creates a second approval request and, once approved, a duplicate.
The final check
Section titled “The final check”Approval is not the last step. Right before an approved or scheduled message leaves, the release
service re-reads the current state: pauses, 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
waits or is blocked (policy_changed, principal_revoked, …); it is never sent on a stale approval.
Branding
Section titled “Branding”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. These are on for every organization on the simail mail domain.