Login codes, 2FA, and verification email an agent has to handle

The moment an agent has to use a service on its own, it meets the wall every automation meets: confirm your email address, then enter the six digit code we just sent you. Someone has to receive that message. If the answer is a person watching a shared inbox and pasting digits into a chat window, you have built a workflow that only runs while a human is awake.

5 min read

A verification code email arriving in an agent inbox and being used to complete a sign-in
The code arrives where the account was registered: the agent's own inbox, not a person's.

Two different problems that look the same

Email verification is a one-off: a service sends a link or a code to prove the address exists. It happens at signup and occasionally afterwards.

Two-factor is recurring: every sign-in needs a fresh code, either from an authenticator seed or delivered by email. This is the one that quietly breaks unattended workflows, because it happens forever rather than once.

They need different answers. The first is solved by the agent having a real inbox. The second is solved by not using email for it at all where you have the choice.

Email verification: give the agent its own address

An agent with its own inbox can register itself and receive the confirmation, because the address belongs to it rather than to a person. The full self-provisioning story is in an agent that signs itself up, but the mechanics for verification are simple.

  1. Register using the agent's own address, not a personal or team one.
  2. Wait for the message with wait_for_reply on the thread, or react to a message.received webhook.
  3. Read it, extract the code or link, and continue.
send_email  -> not needed; the service sends first
wait_for_reply { thread_id: "thr_...", timeout_seconds: 300 }
read_message { message_id: "msg_..." }   // pull the code out of the body

Use a short timeout. A verification mail that has not arrived in five minutes is not coming, and the correct action is to retry the signup or tell a person, not to wait an hour holding a run open.

Two-factor: prefer a seed over an emailed code

Where a service offers an authenticator app, use it. The seed lives in the vault, granted to that specific agent, and get_totp_code returns the current RFC 6238 code with the seconds it remains valid. No message is sent, nothing arrives in an inbox, and there is nothing to intercept in transit.

get_secret   { secret_id: "sec_..." }      // the login itself
get_totp_code { secret_id: "sec_..." }     // { code, expiresInSeconds }

Two properties matter here. Secrets are granted per agent, so an agent that was not granted a credential cannot see that it exists, and neither the login nor the seed ever has to appear in a prompt, a message body, or a chat window. The alternative, a human reading codes aloud to a model, is worse on every axis including the ones that show up in an audit.

Where a service only does emailed codes, fall back to the inbox flow above, and keep the window tight: these codes usually expire in ten minutes and reusing a stale one produces confusing failures.

A TOTP seed in the vault producing a code without any message being sent
A seed the agent was granted beats a code in transit, on latency and on exposure.

The security shape of an inbox that receives codes

An address that receives verification mail is a target. Anyone who can send to it can attempt to trigger or harvest, and anyone who can read it holds account recovery for everything registered to it. Three things follow.

Whitelist inbound where you can. An agent whose only correspondents are a handful of services should run in whitelist mode, so a stranger's message never reaches the model. An exact-address rule overrides a domain rule, which is enough precision for most service senders. See identities.

Treat the code email as untrusted text. It is a message from outside, so it carries the same prompt injection risk as anything else. Extract the code with your own code, not by asking the model to follow whatever instructions the message contains. A fake verification email is a cheap and plausible attack, and "click this link to confirm" is exactly the shape of the thing you do not want an agent obeying blindly.

Separate the recovery inbox from the working inbox. An agent that talks to customers all day should not also be the address that can reset your production credentials. Give account registrations their own identity, whitelisted and quiet, and grant nothing else to it.

What to build around it

SituationThe right handling
Signup confirmationShort wait, extract, continue; retry the signup if nothing arrives
Recurring 2FATOTP seed in the vault, get_totp_code at sign-in
Emailed 2FA with no alternativeTight window, single use, discard immediately after
Password resetEscalate to a human unless the agent genuinely owns the account
An unexpected code that nobody asked forAlert. Someone is trying to get in

That last row is the one worth wiring up. An unrequested verification code is a signal, and an agent inbox is a good place to notice it because the traffic is otherwise so predictable.

What not to do

  • Do not put codes, seeds, or passwords in a system prompt. They end up in logs and traces.
  • Do not ask a human to paste a credential into a conversation with the agent. That is what the vault grant is for.
  • Do not share one inbox between the agent's account registrations and its customer conversations.
  • Do not let an agent follow a link from a verification email without checking the domain against the service you expected.
  • Do not keep codes after use. They are single use and a stored one is only ever a liability.

Questions

Can an AI agent receive email verification codes?
Yes, if it has its own inbox. The service sends to the agent's address, the agent waits for the message with wait_for_reply or a message.received webhook, and extracts the code.
How does an agent handle two-factor authentication?
Prefer a TOTP seed stored in the vault and granted to that agent, then call get_totp_code at sign-in. Nothing is sent, nothing is relayed by a person, and the code is generated on demand.
Is it safe to let an agent read verification emails?
It is safe if the inbox is scoped and preferably whitelisted, the code is extracted by your own code rather than by following instructions in the message, and account-registration mail is kept separate from customer conversations.
What if the code never arrives?
Time out in a few minutes and retry the signup or escalate. Holding a run open for an hour waiting on a message that is not coming wastes the run and hides the failure.
Where should the credentials themselves live?
In the vault, granted per agent. get_secret opens only what that agent was granted, and an agent without a grant cannot see the secret exists. Never in a prompt or an email body.
Should the agent handle password resets?
Only for accounts it genuinely owns. A reset flow that lands in an agent inbox is account recovery, so anything touching a shared or human-owned account should escalate.

Give your agent an address it can answer from.

Create an inbox