AI agent workflows often involve waiting for external events before proceeding. Email verification is the most common example, but the pattern generalizes: email as a state machine, where each incoming message advances the workflow to the next state.
The Pattern
states = {
"awaiting_verification": handle_verification_email,
"awaiting_reply": handle_human_reply,
"awaiting_approval": handle_approval_email,
"complete": None
}
async def run_workflow(inbox_id):
state = "awaiting_verification"
while state != "complete":
email = await wait_for_email(inbox_id)
next_state_fn = states.get(state)
if next_state_fn:
state = await next_state_fn(email)
Real Example: Approval Workflow
- Agent sends a document to a human for review
- Agent waits for an email with "approved" or "rejected" in the subject
- If approved, agent proceeds with next steps
- If rejected, agent revises the document and resends
async def handle_approval_email(email):
subject = (email.get("subject") or "").lower()
if "approved" in subject:
return "complete"
elif "rejected" in subject:
await revise_and_resend()
return "awaiting_approval" # Back to waiting
return "awaiting_approval" # Unknown email, keep waiting
Why Email Works Well as State
- Email is asynchronous by nature, matching the async nature of agent workflows
- Email threads preserve conversation history automatically
- Humans are comfortable with email, making human-in-the-loop workflows natural
- Email is universal: no special client or app needed on the human side
Durability
Unlike in-memory state, email-driven workflows survive process restarts. If your agent process crashes, the emails are still in the inbox waiting. The agent can resume by reading the inbox on restart.