AI agents
How to let an AI agent send email safely
Let an agent send email by giving it a narrowly scoped API key rather than your account, and by putting the same gates in front of it that you'd put in front of any untrusted client: a verified-domain check, per-workspace rate limits, idempotency keys so a retry loop can't send twice, and an approval step for anything one-to-many.
How to let an AI agent send email safely
The concrete controls that make agent-initiated email safe: scoped credentials, a verified-domain gate, idempotency, approval before send, and an audit trail.
An agent that can send email is a client that composes its own requests. That is genuinely useful — drafting a follow-up, sending a report, notifying a user — and genuinely risky, because the failure modes differ from a human's. Agents retry, loop, and occasionally misunderstand scope in ways a person wouldn't.
Give it a scoped key, not your account
The single most important control. Create a dedicated key with only the capability the agent needs, and revoke it independently of everything else. A key that can send email should not also be able to delete contacts or read your logs.
- One key per agent, so revoking one doesn't disrupt the others
- Only the scopes it needs — emails:send for sending, nothing more
- Never a full-access key, and never the key your application uses
The domain gate does the heavy lifting
An agent can only send from a domain already verified in the workspace that owns its key. It cannot add a domain, cannot verify one, and cannot spoof an address on a domain you don't control — the API returns 403 regardless of how convincingly it asks. This is the control that makes the whole arrangement tractable: the worst case is unwanted mail from your own verified domain, not impersonation of someone else.
Idempotency, because agents retry
Agent frameworks retry on timeouts and ambiguous errors, and an agent that isn't sure whether a send succeeded will often try again. Send an Idempotency-Key and a retry within 24 hours returns the original result instead of a second email:
curl https://www.unitpost.com/api/v1/emails \
-H "Authorization: Bearer pk_live_..." \
-H "Idempotency-Key: report-run-8f21" \
-H "Content-Type: application/json" \
-d '{"from":"Acme <hello@acme.com>","to":"user@example.com","subject":"Your report","html":"<p>Attached.</p>"}'Derive the key from the task, not the attempt
Use something stable for the unit of work — a run id, a ticket id — so every retry of the same logical send reuses it. A random key per attempt provides no protection at all.
Require approval for anything one-to-many
A mistake sent to one person is a mistake. The same mistake sent to a segment is an incident. One-to-many marketing sends are refused on the transactional API entirely — they have to go through campaigns, which has an explicit send step. That structural boundary means an agent with emails:send cannot mail your whole list even if it decides to.
Keep the audit trail
Every authenticated API request is logged, so 'what did the agent actually send' is answerable after the fact. When you're deciding how much autonomy to grant, being able to review what it did is what makes the decision reversible.
Frequently asked questions
What stops an agent from emailing the wrong person?
Nothing structural — that's a prompt and application-design problem, and it's the residual risk you're accepting. What the platform does prevent is worse outcomes: sending from a domain you don't own, mailing a whole segment through the transactional API, sending duplicates on retry, and mailing addresses that previously bounced or complained.
Can I limit an agent to specific recipients?
Not through API scopes, which are capability-based rather than recipient-based. If you need that, keep the recipient list on your side: have the agent call your own endpoint that validates the recipient, and let that endpoint hold the Unitpost key. The agent never sees a credential that can send arbitrarily.
Should an agent use its own API key or share the app's?
Its own, always. A separate key means you can revoke the agent's access the moment something looks wrong without taking down your application's sending, and the request log tells you unambiguously which sends came from the agent.