How does email-based human approval work?
An email human-in-the-loop workflow puts a human decision before an action executes. Sending someone a notification after an agent has acted is not an approval gate. Neither is simply adding a colleague to an email thread.
Consider a support agent that drafts a customer reply. It reads the incoming message and proposes recipients, a subject, and a body. Your application stores that proposal, requests review by email, and waits. An authorized reviewer inspects the exact action before a separate executor sends it.
The pause belongs in durable application state. You don't need to keep a model session running while someone reviews the message. Resume the stored task after a valid decision, without asking the agent to regenerate the approved reply.
For the broader mailbox architecture, see email for AI agents using existing mailboxes. For the overall agent design, see building an email agent with approval boundaries. Here, the focus is the approval contract between drafting and execution.

Which parts belong to Mailera and which belong to your application?
Use Mailera MCP for the drafting agent’s mailbox access and a separate server-side REST executor for sending.
| Responsibility | Owner |
|---|---|
| Read incoming messages | Mailera list_messages and get_message, using read scope |
| Store the proposed action and its version | Your application |
| Authenticate reviewers and check their authority | Your application |
| Record approval, rejection, and expiry | Your application |
| Claim an approved action for execution | Your application |
| Send the authorized message and inspect its send attempt | Mailera REST, called by your controlled executor |
Your application implements the approval engine: durable approval state, reviewer authentication, and execution authorization.
The MCP tools specification recommends human oversight, confirmation for sensitive operations, and showing tool inputs before invocation. It does not mandate a particular interaction model. Store approval state in your application and require the executor to validate the recorded decision before invoking a sending operation.
Mailera’s send_email and reply_to_email tools use send scope. Do not expose them, or send credentials, to the unapproved drafting agent. The Mailera MCP tool guide explains the tools by task; tool availability alone is not an approval boundary.
A message.received webhook can tell your application that mail arrived. It is not an approval-decision event. Keep that distinction when connecting the Mailera developer interfaces to your workflow.
What must an approval record contain?
Store the proposal before sending the review request. The following names are application design choices, not Mailera API fields.
| Application field | What to store |
|---|---|
request_id, action_type | An opaque request identifier and the proposed operation, such as sending a support reply |
action_snapshot | Sending mailbox, exact To/Cc/Bcc recipients, subject, body, attachment contents or immutable references, and reply target |
proposal_version or proposal_hash | A binding to every material action parameter |
authorized_reviewer | The application identity or policy defining who may decide |
expires_at | The deadline enforced by your application |
decision | State, reviewer identity, decision time, and approved version |
execution_reference | Stable idempotency key, worker claim, send-attempt reference, and outcome |
Do not let an attachment reference point to a file that can change after review. Any change to recipients, content, attachments, or other material parameters requires a new proposal and fresh approval.
Use explicit transitions. These state names also belong to your application:
| From | To | Required condition |
|---|---|---|
pending | approved or rejected | Authorized reviewer, unchanged proposal, before expiry |
pending or unclaimed approved | expired | Deadline reached |
approved | executing | Atomic claim of the unchanged, unexpired proposal |
executing | completed, failed, or reconciliation-required | Recorded execution result |
Make both decision recording and execution claims atomic. A read followed by an unconditional write lets concurrent workers act on the same old state.
How do you build the approval flow step by step?
- Connect a mailbox you control and separate credentials. Mailera connects existing mailboxes; it does not create mailboxes or addresses. In Settings, open the API key tab and select Create key. Give the drafting key only Read, restrict Mailbox scope to the relevant group, and set Expiration. Use Copy MCP config for the agent client. Keep the executor’s separate Send messages credential outside the agent context.

- Read, draft, and persist. Use
list_messagesandget_messageto read the support request. Have the agent propose a reply, then store the immutable action snapshot in your application database. Do not use the agent’s conversation history as the approval record. - Request review through a trusted notifier. Resolve the reviewer from application policy, not from the incoming email or model-generated text. Email a short action summary, the expiry, and an opaque reference to an application-hosted review page. Keep sensitive customer content on that authenticated page rather than copying it into the notification.
- Require sign-in and explicit confirmation. On the review page, authenticate the person and verify their authority for this request. Display the sending mailbox, all recipients, and the exact content and attachments. Fetching the link, including through a preview, must never approve or execute anything. Require a protected, explicit confirmation action. Possessing the link is not enough.
- Commit the decision atomically. Within a transaction, load the pending record, check reviewer authorization and expiry, and compare the displayed proposal version with the stored version. Record the decision only if all checks pass. Reject stale or conflicting submissions rather than overwriting an earlier decision.
- Claim and execute the stored action. A separate worker atomically changes an eligible
approvedrecord toexecutingand persists its stable idempotency key before making the network request. It callsPOST /mailboxes/{id}/sendusing the stored action, not newly generated text. The endpoint requiressendscope and acceptsIdempotency-Key. Use the Mailera API documentation for the send request schema. - Record the outcome separately. Retain the send-attempt reference and inspect
GET /sends/{id}. Mailera reportsqueued,sending,sent,failed, orunknown. Keep approval and execution results separate: “approved” must not silently become “sent.” Preserve enough state to reconcile a crash or timeout without creating another execution.
To enforce the gate, load the stored proposal, validate the decision, atomically claim execution, then send that snapshot. Do not resume by handing a send-capable agent a message saying “the human approved.”
Can the reviewer approve by replying to the email?
For consequential actions, use an authenticated review link. Reply-based approval needs additional identity and parsing policy, even when the response looks obvious.
| Concern | Authenticated review page | Reply-based decision |
|---|---|---|
| Identity | Check the signed-in user against policy | Apply a documented identity policy beyond sender text |
| Decision parsing | Explicit approve or reject control | Require a strict decision grammar |
| Forwarding | Recheck authorization for whoever opens the link | Do not treat a forwarded request as delegated authority |
| Reviewer effort | Sign in and inspect the exact action | Reply in email, with exceptions routed to review |
A display name, From address, or matching thread alone should not authorize execution. RFC 5322 defines Internet message contents, not the delivery envelope. Treat message metadata as input to your policy, not as proof of a human decision.
If you accept replies, correlate each one with a pending request and its proposal version. Require an explicit decision grammar. Email authentication can inform your identity policy, but do not use it as proof that a particular human intended the exact action.
Send ambiguous responses, quoted approval text, delegated decisions, and conflicting replies to manual review. Never ask the model to infer consent from “looks fine, but change the recipient.” That is a requested revision, not approval of the stored proposal.
What commonly breaks, and how should you recover?
| Failure | Recovery rule |
|---|---|
| No decision arrives | Expire or escalate under application policy. Silence is not approval. |
| Notification is delayed, lands in Junk, or the mailbox disconnects | Surface the problem and offer authenticated manual review. Mailera does not guarantee inbox placement; do not make the workflow depend on immediate arrival. |
| A reply or webhook arrives twice | Deduplicate transport events, then independently enforce one-time decision and execution claims. |
| Workers race to execute | Allow only one atomic claim of the approved proposal. |
| The draft changes | Create a new version and request fresh approval. |
| The send result is uncertain | Enter reconciliation-required and inspect the send attempt before retrying. |
Mailera’s Idempotency-Key window is 24 hours. Reuse the same persisted key for retries of the same execution within that window. Keep durable application state beyond it; do not assume a retry after the window will be deduplicated.
A timeout is not proof that nothing was sent. If you lack a usable send reference or the status remains unknown, stop automatic resends and reconcile. Human approval, API acceptance, a sent status, and recipient delivery are different checkpoints. None establishes that the recipient read the message.
Before deployment, test approval and rejection, expiry, unauthorized review, duplicate events, concurrent workers, changed proposals, and uncertain send outcomes. Use mailboxes you control. Check that each case leaves a durable record and cannot trigger an extra send.
How do you keep incoming email from becoming an agent instruction?
Email bodies and attachments are untrusted data, not instructions. Ignore embedded requests to reveal credentials, change tools, redirect approval notifications, or bypass review.
Enforce the boundary through application code and credentials, not only a system prompt. Give the drafting agent a narrowly scoped Read key. Keep notification routing in trusted configuration, and let the executor accept only a stored proposal that passed the gate. Require confirmation of exact recipients, body, and attachments.
Use key expiration and revocation as operational controls. Review Mailera’s security information alongside your application’s access policy. Revoking a key does not replace checking reviewer authority on each request.
For incoming webhooks, implement signature validation and replay protections according to the current Mailera documentation. Store the signing secret securely when creating the webhook; Mailera returns it only once. A valid webhook authenticates a transport event, not an approval.
Log the reviewer, proposal version, state transitions, and execution reference without logging credentials. That record should let an operator answer one concrete question: did the executor send exactly what this authorized person approved?
Let AI agents use your mailbox via MCP
Add Mailera's MCP server to Claude, Cursor or VS Code so agents can read, categorize and reply to email messages.
Learn how to use MCP








