When your AI agent sends emails that affect individuals, GDPR requires human oversight. MultiMail's gated_send mode enforces that review and logs every decision.
GDPR Article 22 grants individuals the right not to be subject to decisions based solely on automated processing when those decisions produce legal or similarly significant effects. AI agents sending emails about loan decisions, job applications, account terminations, or insurance claims likely trigger this right. Sending those emails without a human in the review loop exposes your organization to enforcement action under Article 83—fines up to €20 million or 4% of global annual turnover. Many teams ship AI email pipelines that technically satisfy their internal review SOP, but have no audit trail proving a human actually reviewed and approved each outbound message before delivery.
MultiMail's gated_send oversight mode holds every outbound email in a pending queue until a human reviewer explicitly approves or rejects it via the API or dashboard. The approve/reject action, the reviewer identity, and the timestamp are written to an immutable audit log that survives the lifetime of the email. This gives you a verifiable chain of evidence that a human exercised meaningful control over each AI-drafted message—directly satisfying Article 22's human oversight requirement. The AI agent drafts and classifies; a human decides whether to send. Your audit log proves it.
Before your agent drafts anything, call the decide_email tool or POST to /v1/emails/classify to tag whether the outbound email carries a significant automated decision (e.g., application outcome, credit limit change, account action). This classification drives downstream routing and is included in the audit record.
Create or update the sending mailbox with oversight_mode set to gated_send via POST /v1/mailboxes. Every email sent from this mailbox is held in the pending queue regardless of which agent or pipeline originates it—no per-call flag required.
Your agent calls send_email (POST /v1/emails/send) as normal. Because the mailbox is in gated_send mode, the API returns a 202 with a pending email ID rather than delivering immediately. The draft is stored server-side with the agent's decision metadata attached.
A human reviewer calls GET /v1/emails/pending to see the queue, reads the draft and classification, then calls POST /v1/emails/{id}/approve or /v1/emails/{id}/reject. The approval event records the reviewer's authenticated identity and timestamp.
On approval, MultiMail delivers the email and finalizes the audit record: agent ID, draft timestamp, classifier output, reviewer ID, review timestamp, and delivery confirmation. This record is available via GET /v1/emails/{id}/audit and is immutable after delivery.
import httpx
client = httpx.Client(
base_url="https://api.multimail.dev",
headers={"Authorization": "Bearer $MULTIMAIL_API_KEY"}
)
"cm"># Create mailbox with gated_send — all sends require human approval
response = client.post("/v1/mailboxes", json={
"address": "[email protected]",
"display_name": "YourCompany Decisions",
"oversight_mode": "gated_send",
"metadata": {
"gdpr_article22_scope": True,
"reviewer_team": "compliance"
}
})
mailbox = response.json()
print(f"Mailbox {mailbox[&"cm">#039;id']} created with oversight: {mailbox['oversight_mode']}")
"cm"># oversight_mode: gated_send — emails queue for review, never deliver without approvalConfigure a mailbox with gated_send oversight so every outbound email is held for human review automatically.
from multimail_sdk import MultimailClient
client = MultimailClient(api_key="$MULTIMAIL_API_KEY")
"cm"># Agent drafts the decision email — gated_send mailbox holds it automatically
result = client.send_email(
from_address="[email protected]",
to="[email protected]",
subject="Your application — decision notification",
body=(
"After review by our team, we would like to inform you that your "
"application has been assessed. Please log in to your account to "
"view the full decision and your options for next steps."
),
metadata={
"automated_decision": True,
"gdpr_article22": True,
"application_id": "APP-2026-00412",
"agent_id": "screening-agent-v2"
}
)
"cm"># Returns 202 — email is queued, not yet delivered
print(f"Status: {result.status}")
"cm"># Status: pending
print(f"Pending email ID: {result.email_id}")
"cm"># Pending email ID: em_01J9X... — reviewer must approve before deliveryThe agent sends an email that enters the pending queue. The 202 response confirms it is held, not delivered.
import httpx
client = httpx.Client(
base_url="https://api.multimail.dev",
headers={"Authorization": "Bearer $MULTIMAIL_API_KEY"}
)
"cm"># Pull pending emails tagged as Article 22 scope
pending = client.get("/v1/emails/pending", params={
"mailbox": "[email protected]",
"metadata[gdpr_article22]": True
}).json()
for email in pending["emails"]:
print(f"ID: {email[&"cm">#039;id']}")
print(f"To: {email[&"cm">#039;to']}")
print(f"Subject: {email[&"cm">#039;subject']}")
print(f"Agent: {email[&"cm">#039;metadata']['agent_id']}")
print(f"Application: {email[&"cm">#039;metadata']['application_id']}")
print()
# Human reviewer decision — identity captured from auth token
email_id = email["id"]
response = client.post(f"/v1/emails/{email_id}/approve", json={
"reviewer_note": "Reviewed application APP-2026-00412. Decision is accurate."
})
result = response.json()
print(f"Approved by: {result[&"cm">#039;audit']['reviewer_id']}")
print(f"Reviewed at: {result[&"cm">#039;audit']['reviewed_at']}")
print(f"Delivered at: {result[&"cm">#039;audit']['delivered_at']}")A human compliance reviewer fetches pending emails, inspects the draft, and approves. The audit record is finalized on approval.
import httpx
client = httpx.Client(
base_url="https://api.multimail.dev",
headers={"Authorization": "Bearer $MULTIMAIL_API_KEY"}
)
email_id = "em_01J9X4KM2VPNQ8W3R7T"
audit = client.get(f"/v1/emails/{email_id}/audit").json()
print("=== GDPR Article 22 Audit Record ===")
print(f"Email ID: {audit[&"cm">#039;email_id']}")
print(f"Agent ID: {audit[&"cm">#039;agent_id']}")
print(f"Drafted at: {audit[&"cm">#039;drafted_at']}")
print(f"Decision type: {audit[&"cm">#039;metadata']['gdpr_article22']}")
print(f"Reviewer ID: {audit[&"cm">#039;reviewer_id']}")
print(f"Reviewer note: {audit[&"cm">#039;reviewer_note']}")
print(f"Review decision: {audit[&"cm">#039;review_decision']}")
print(f"Reviewed at: {audit[&"cm">#039;reviewed_at']}")
print(f"Delivered at: {audit[&"cm">#039;delivered_at']}")
print(f"Recipient: {audit[&"cm">#039;to']}")
"cm"># This record is immutable — safe to present to DPA or data subject on SARFetch the complete audit record for a delivered email—agent identity, review decision, timestamps—for compliance evidence or DPA response.
Every outbound email that triggers Article 22 has an immutable audit record showing which human reviewed it, what decision they made, and when. This is the evidence a Data Protection Authority will ask for.
gated_send is enforced at the infrastructure level. A misconfigured agent, a rushed deployment, or a forgotten conditional cannot bypass the review queue—the mailbox configuration is the control, not application code.
When a reviewer rejects a draft via POST /v1/emails/{id}/reject, they can include a structured reason. Your agent can read this via the webhook or GET /v1/emails/{id} and revise the draft before resubmitting, reducing reviewer round-trips.
Configure a webhook on the email.pending event to route new drafts to your existing compliance tooling—Slack, PagerDuty, Jira, or a custom dashboard. Reviewers do not need to poll a separate system.
Issue reviewer API keys with approve_email scope only—they cannot send new emails or read unrelated mailboxes. This enforces separation of duties between the AI agent role and the human oversight role.
Email infrastructure built for AI agents. Verifiable identity, graduated oversight, and a 50-tool MCP server. Formally verified in Lean 4.