How do I build a human-in-the-loop workflow?
AgentMail provides several mechanisms for keeping humans involved when agents send emails. You can combine these approaches to match the level of oversight your workflow requires.
1. CC or BCC a human on every email
The simplest approach: copy a human on every email your agent sends so they have full visibility.
The manager sees every outgoing email and can step in if something looks wrong. Use bcc instead of cc if you want the oversight to be invisible to the recipient.
2. Drafts for review before sending
Use Drafts to let your agent compose emails that a human reviews and approves before they go out. This is ideal for high-stakes emails like contracts, legal communications, or financial matters.
A draft is only an approval step if the agent cannot send on its own. If the agent’s API key can send (messages.send, replies, forwards, or drafts.send), it can skip the review. Give the agent a key with scoped permissions that grants draft_create (plus draft_read and draft_update if it revises drafts) but not message_send, message_reply, or draft_send. Keep draft_send for the key your approval tool uses. Scheduling a draft with send_at also requires draft_send.
You can also list drafts across every inbox your API key can access, which is useful for building a central approval dashboard. Two things to keep in mind:
drafts.list()returns every draft unless you filter it, so filter by the label your agent puts on drafts awaiting review.- Results come one page at a time.
countis the number of drafts in the current page, not the total, so follownext_page_tokenuntil it is absent.
For more details, see the Drafts core concept documentation.
3. Labels for escalation
Use labels to flag messages that need human attention. Your agent can detect situations it cannot handle and tag them for review.
Then build a dashboard or scheduled job that queries for flagged messages:
4. Allowlists as guardrails
Use a send allowlist to restrict which addresses your agent can email. If the agent tries to send to an address or domain not on the list, AgentMail rejects the request with a 403 and error code message_rejected, and the email does not go out.
This acts as a hard safety boundary. Your agent can only email recipients you have explicitly approved, regardless of what the agent logic tries to do, as long as the agent’s API key cannot edit lists (list_entry_create and list_entry_delete).
Best practices
- Start with CC + drafts for new agents until you trust their behavior
- Graduate to autonomous sending for routine emails, and keep drafts for high-value communications
- Always have an escalation path: agents should know when to stop and ask for help
- Use labels consistently across your agents so dashboards and alerting work reliably
- Combine approaches: for example, let the agent send autonomously from an inbox with an inbox-level send allowlist of known recipients, route everything else through drafts in a separate inbox, and CC a human on everything during the first week. Give the agent an inbox-scoped key for each inbox, and leave the send permissions off the drafts inbox’s key; a single key that can send would let the agent skip the drafts. Keep the two inboxes separate because a send allowlist also applies when a draft is sent, so an approved draft to a recipient outside the list would still be rejected.
