TL;DR: AI agents treat email as a bidirectional action layer — not just a delivery mechanism. They send contextual messages, parse inbound replies, classify intent, trigger workflows, and maintain conversational state across threads. This post explains the architecture behind that shift and the engineering patterns that make it reliable.

AI in email has moved well past "send a notification when something happens." Modern agents use email as a full action layer: they initiate outreach, parse structured data from replies, classify intent, route decisions, and close loops autonomously — all over SMTP and IMAP primitives that have existed for decades. The interesting engineering lives in the layer between the raw protocol and the agent's reasoning loop.
This post covers what that architecture actually looks like, where the hard problems are, and how to build systems that treat email as a durable, bidirectional communication substrate rather than a one-way pipe.
What "email as an action layer" actually means
The action layer framing means email is a surface where agents both produce and consume meaningful events, not just emit fire-and-forget messages. A notification channel is unidirectional: something happens, a message goes out, done. An action layer is bidirectional and stateful: the agent sends a message, waits for a structured response, interprets it, and takes a follow-on action.
Concretely, this looks like:
- Initiating multi-step workflows — an agent emails a vendor to request a quote, receives the PDF attachment, extracts line items, and routes an approval request to a human stakeholder
- Parsing replies as structured input — treating a reply body as an instruction set ("approve", "reject with comment", "escalate") rather than opaque text
- Maintaining thread state — using
Message-IDandIn-Reply-Toheaders to correlate messages to the originating workflow run, even across days - Triggering downstream actions — a classified inbound email fires a webhook that updates a database record, creates a ticket, or resumes a paused agent run
This is qualitatively different from a CRM sending a welcome email or a SaaS app emailing a password reset link. Those are stateless emissions. Agent email is stateful, event-driven, and often involves LLM inference on message content.
The four functional roles of an email-native agent
1. Sender
Agents send email as actors with intent, not as templates triggered by row inserts. The engineering difference is that the sending logic is inside the agent's reasoning loop. The agent decides when to send, what to say (often LLM-generated), and what reply to expect.
This creates requirements that transactional email infrastructure doesn't address well:
- Per-agent sender identity —
agent-procurement@company.aineeds its own SPF/DKIM alignment so replies route back correctly - Reply-To correlation — using a unique
Reply-Toaddress per workflow run (e.g.,reply+run_abc123@inbound.company.ai) to correlate responses without parsing thread headers - Deliverability for automated senders — high-volume agent senders need dedicated IP pools and warm-up schedules, not shared pools sized for human-scale outbound
2. Receiver
Receiving email as an agent means you need inbound email parsed to a structured webhook payload before the LLM ever sees it. Raw MIME is not agent-friendly. The inbound email parsing pipeline should hand your agent a JSON object with extracted body text, attachment metadata, sender verification results, and threading headers, not a raw .eml blob.
The parsing layer needs to handle:
- Quoted reply stripping — isolating the human's new text from the full thread history
- Attachment extraction — MIME part decoding, file type detection, binary → base64 or storage URL
- SPF/DKIM verification — so your agent knows whether the sender is who they claim to be before acting on instructions
- Threading correlation — extracting
In-Reply-ToandReferencesto map inbound messages to the originating outbound run
3. Classifier
Not every inbound email needs the same response. An agent inbox might receive vendor quotes, human approvals, auto-replies, bounce notifications, and spam — all at the same address. Classification determines which pipeline handles each message.
Email classification at the infrastructure layer (before your agent loop runs) is more efficient than feeding every message to an LLM. Rule-based pre-filters handle obvious cases (auto-reply headers, bounce MIME types, SPF failures). LLM classification runs on the remainder, extracting intent categories and confidence scores.
A practical classification schema for a procurement agent:
| Category | Signal | Downstream Action |
|---|---|---|
vendor_quote |
Attachment present + body matches quote template | Extract PDF, run OCR, trigger approval flow |
human_approval |
Reply from internal domain + contains "approve"/"reject" | Resume paused workflow run |
auto_reply |
Auto-Submitted: auto-replied header |
Discard, log, do not trigger agent |
bounce |
MIME type message/delivery-status |
Mark send as failed, retry or escalate |
unknown |
None of the above | Queue for human review |
4. Reasoner
The reasoner is the LLM layer that interprets parsed, classified email content and decides what to do next. This is where email becomes genuinely intelligent rather than just automated.
The reasoner needs:
- Structured context — the parsed email payload, thread history, and current workflow state as LLM context
- Tool access — ability to call APIs (update a record, send a reply, create a ticket) as function calls or MCP tool invocations
- Decision logging — every classification and action decision should be persisted so the system is auditable
MCP (Model Context Protocol) is increasingly the standard interface here. An MCP-native email server exposes send_email, read_inbox, get_thread, and classify_message as tools that an LLM host (Claude, GPT-4o, etc.) can call natively in its tool loop — no custom integration glue required.
Thread state and correlation: the hard part
Maintaining state across an asynchronous email exchange is the most underestimated engineering challenge here. Email is inherently async — replies can arrive minutes, hours, or days after the original message. Your agent needs to correlate a reply received at 2 PM to a workflow that started at 9 AM and may have spent hours doing other work in between.
Two mechanisms:
1. Unique Reply-To addresses
Embed a run or workflow ID in the Reply-To header: Reply-To: reply+wf_8f3a2c@inbound.yourdomain.com. When the inbound webhook fires on that address, you extract wf_8f3a2c from the local part and look up the workflow state. This is more reliable than header parsing because it works even when mail clients mangle In-Reply-To.
2. RFC 2822 threading headers
For agents that need to maintain visible thread continuity (so human participants see a coherent conversation in their mail client), you must set In-Reply-To: <original-message-id> and append to the References header chain. This keeps the exchange in one thread visually while your system correlates by message ID internally.
Use both. The unique Reply-To gives you reliable machine correlation; the threading headers give human participants a readable conversation.
Message-ID: <wf_8f3a2c.msg_001@mail.yourdomain.com>
Reply-To: reply+wf_8f3a2c@inbound.yourdomain.com
In-Reply-To: <vendor-original-msg-id@vendordomain.com>
References: <vendor-original-msg-id@vendordomain.com>
The inbound webhook contract
Every inbound email should arrive at your agent as a structured HTTP POST. The payload your webhook handler receives should be deterministic and parseable without LLM intervention for the structural fields:
{
"event": "inbound.received",
"message_id": "<abc123@mail.example.com>",
"in_reply_to": "<wf_8f3a2c.msg_001@mail.yourdomain.com>",
"thread_id": "wf_8f3a2c",
"from": { "address": "vendor@acme.com", "name": "ACME Procurement" },
"to": [{ "address": "reply+wf_8f3a2c@inbound.yourdomain.com" }],
"subject": "Re: Quote Request #Q-2891",
"body_text": "Please find attached our quote. Total: $4,200 net 30.",
"body_html": "<p>Please find attached...</p>",
"attachments": [
{
"filename": "quote_Q2891.pdf",
"content_type": "application/pdf",
"size_bytes": 84321,
"url": "https://storage.example.com/attachments/abc123/quote_Q2891.pdf"
}
],
"spf": "pass",
"dkim": "pass",
"classification": "vendor_quote",
"received_at": "2026-08-29T14:32:11Z"
}
The thread_id field extracted from the Reply-To local part is what lets your agent resume the right workflow. The classification field (if your infrastructure provides it) means your agent can skip the classification step and go straight to action.
Why deliverability is an agent problem, not just a marketing problem
Agent senders often fail deliverability checks because they're sending at machine speed with machine-generated content — patterns that spam filters are trained to catch. According to Google's Postmaster Tools documentation, authenticated sending (SPF + DKIM + DMARC alignment) is a hard requirement for maintaining sender reputation at Gmail scale.
For agents specifically:
- Domain alignment matters — the
Fromdomain must match the DKIM signing domain. An agent sending fromagent@yourdomain.comsigned by a third-party ESP's DKIM key will fail alignment checks. - Volume ramp-up — new IPs need warm-up over 4-6 weeks. An agent that suddenly sends 10,000 emails from a cold IP will see immediate reputation damage.
- Content consistency — LLM-generated content can produce unusual n-gram patterns. Running outbound agent email through a spam scoring check (SpamAssassin or equivalent) before delivery catches issues before Gmail does.
Platforms like Mails.ai provide dedicated IP pools specifically sized for automated agent senders — separate from shared pools used by human marketing campaigns, which have different volume and content profiles.
Building the agent email loop: a reference architecture
sequenceDiagram
participant Agent as Agent Loop
participant EmailAPI as Email API
participant Inbound as Inbound Parser
participant LLM as LLM Reasoner
Agent->>EmailAPI: send with Reply-To wf_abc123
EmailAPI->>Inbound: routes reply to webhook
Inbound->>Agent: POST parsed payload thread_id wf_abc123
Agent->>LLM: classify and extract intent
LLM->>Agent: intent approved amount 4200
Agent->>Agent: resume workflow update record
Agent->>EmailAPI: send confirmation reply
The key architectural property here is that the agent loop is event-driven, not polling-based. The webhook POST from the inbound parser resumes the workflow. No IMAP polling, no cron jobs checking for new mail, no synthetic delays.
What this means for infrastructure selection
Most transactional email providers are built for the outbound-only, stateless case. They don't expose:
- Inbound parsing to webhook with threading correlation
- Per-message classification as a platform feature
- MCP tool server for LLM host integration
- Dedicated IP pools for automated (non-marketing) senders
If you're evaluating infrastructure for an email-native agent, the checklist looks different from "which ESP has the best deliverability dashboard." You need bidirectional infrastructure with structured inbound events, not just an outbound SMTP relay. The Mails.ai agent email platform is built explicitly for this pattern — inbound parsing, classification, MCP server, and outbound deliverability as a unified stack.
For teams currently on Resend or SendGrid and hitting the limitations of outbound-only infrastructure, the agent email use cases overview covers the patterns that require a different approach.
Frequently Asked Questions
Why not just use IMAP polling to read replies instead of inbound webhooks?
IMAP polling introduces latency, burns connection resources, and requires you to manage seen/unseen state manually. A webhook-based inbound pipeline delivers the parsed message to your agent within seconds of receipt, with zero polling overhead. For agents that need to resume workflows on reply, the latency difference matters — a vendor quote that arrives at 9 AM shouldn't wait until your 15-minute IMAP poll to trigger the approval flow.
How do you prevent an agent from acting on spoofed or forged inbound email?
Verify SPF and DKIM on every inbound message before passing it to your agent. Your inbound parsing infrastructure should expose these results in the webhook payload ("spf": "pass", "dkim": "pass"). If either check fails and the message claims to be from a trusted domain (e.g., an internal approver), treat it as untrusted and route it to human review rather than triggering an automated action. Never act on instructions from a message with failed authentication if that message is claiming elevated trust.
How does an agent maintain a coherent email thread that humans can read?
Set In-Reply-To to the Message-ID of the previous message in the thread, and append that Message-ID to the References header. Mail clients use these headers to group messages into threads. If your agent is continuing a human-initiated conversation, parse the original Message-ID from the inbound webhook payload and use it in subsequent sends.
What's the difference between an agent using email vs. a traditional email automation tool?
Traditional automation tools (Zapier, Make, Mailchimp automations) follow fixed decision trees. An email-native agent uses LLM reasoning to interpret unstructured reply content, make contextual decisions, and generate responses — it can handle cases the original developer didn't anticipate. The infrastructure requirements converge (inbound parsing, webhooks, threading), but the decision logic layer is fundamentally different.
Can an agent handle attachments from inbound email reliably?
Yes, but it requires a parsing layer that decodes MIME parts and exposes attachings as accessible URLs or base64 blobs rather than raw MIME. For PDF attachments specifically, the agent needs an OCR or document parsing step before the LLM can reason about the content. Structure the pipeline as: inbound MIME → attachment extraction → document parsing → structured JSON → LLM context. Don't pass raw binary to an LLM.
How do you handle the case where no reply arrives — timeouts and retries?
Store the expected-reply deadline (e.g., reply_deadline: 2026-08-30T17:00:00Z) when you send the initial message. Run a scheduled job that queries for workflow runs past their deadline and triggers a configurable escalation path — send a follow-up, notify a human, or mark the task as stalled. This is workflow state management, not email infrastructure. Your email layer just needs to surface whether a reply was received; the agent loop handles the timeout logic.