Skip to content
Engineering

Receive Emails as JSON for Safer Agent Automation

| | 12 min read
Receive Emails as JSON for Safer Agent Automation
Receive Emails as JSON for Safer Agent Automation

Agent automation becomes fragile when email is treated like a visual inbox. Raw messages contain MIME boundaries, nested HTML, sender-controlled headers, tracking links, forwarded content, and human-oriented copy. An LLM agent can misread that noise, follow the wrong link, leak context into a form, or retry until it creates a loop.

The safer pattern is to receive emails as JSON before they ever reach the agent. JSON does not magically make email trusted, but it gives your automation a typed boundary: stable IDs, normalized bodies, explicit routing metadata, and extracted artifacts that can be validated before an agent acts.

For AI agents, QA runners, and signup verification flows, that boundary is the difference between “the model read an email” and “the system supplied a narrow, verified tool result.”

Why raw email is a risky input for agents

Email was designed for flexible human communication, not deterministic automation. A single message can contain plain text, HTML, attachments, quoted replies, duplicate headers, encoded subjects, and links that render differently depending on the client. That flexibility is useful for people, but dangerous for agents.

In an agent workflow, inbound email can trigger real actions: account creation, password reset completion, subscription activation, vendor onboarding, or data extraction. If the model sees the full email body, it also sees everything a sender can place in the message, including misleading instructions such as “ignore previous rules,” fake verification links, or content that resembles system prompts.

A JSON-first pipeline reduces that risk by moving interpretation out of the model and into deterministic code. The agent should not be asked to inspect a raw HTML email and decide what to do. It should receive a small result such as: “verification email arrived, from expected sender, for this inbox, with this validated OTP.”

That is a very different security posture.

What changes when emails arrive as JSON

When you receive emails as JSON, your application can separate three concerns that are often mixed together in mailbox automation:

  • Delivery, meaning which inbox received which message and when.
  • Content, meaning what the sender wrote in the subject and body.
  • Artifacts, meaning the specific value automation needs, such as an OTP, magic link, or confirmation token.

This separation matters because these fields have different trust levels. An inbox ID created by your system is much more reliable than a sender-controlled subject line. A derived OTP extracted by a parser and validated against expected shape is safer than asking an LLM to choose a number from a rendered email.

A practical JSON email object should make those boundaries visible.

Field group Example fields Why agents need it Trust level
Delivery identity delivery_id, inbox_id, received_at Dedupe events, route to the right run, enforce deadlines Provider or system observed
Message identity message_id, thread_id Avoid processing the same email twice Useful signal, not enough alone
Routing to, envelope_to, domain, inbox_address Confirm the message reached the intended disposable inbox Provider or SMTP observed
Sender claims from, reply_to, subject Match expected flows, debug failures Sender-controlled
Content text, html, attachments Provide source material for parsers and audit logs Untrusted input
Derived artifacts otp, verification_url, artifact_hash Give agents the minimal thing they need to act Derived and policy-checked
Provenance raw_available, parsed_at, parser_version Support replay, debugging, and parser migrations System generated

The exact schema can vary by provider and workflow. The important design choice is not a specific field name. It is that agents operate on the smallest validated representation, while engineers retain enough structured context to debug failures.

A safer agent automation pipeline

A JSON email pipeline should be built as a series of gates. Each gate reduces ambiguity before the agent is allowed to make a decision.

  1. Create an isolated inbox for the task or attempt.
  2. Trigger the external flow using the generated email address.
  3. Receive the message through a signed webhook or retrieve it through a polling API.
  4. Verify the delivery, normalize the email, and dedupe by stable IDs.
  5. Extract only the needed artifact, such as an OTP or verification URL.
  6. Validate the artifact against policy before exposing it to the agent.
  7. Let the agent continue with a constrained tool result, not the raw message.

The key is that the agent does not own the parsing boundary. Code owns it. The model can decide when to call a tool, but the tool should return a deterministic answer.

For example, an agent-safe result can look like this:

{
  "status": "matched",
  "inbox_id": "inbox_123",
  "received_at": "2026-05-27T21:11:00Z",
  "artifact": {
    "type": "otp",
    "value": "493821",
    "expires_hint": "short_lived"
  },
  "evidence": {
    "delivery_id": "del_456",
    "message_id": "msg_789",
    "matched_sender": true,
    "matched_subject": true
  }
}

That is far safer than passing the full email body into a prompt and asking the model, “What should I click?”

Webhooks first, polling as a controlled fallback

For most agent automation, real-time webhooks are the cleanest way to receive email as JSON. They reduce latency, avoid wasteful loops, and let your system react when the message actually arrives. A webhook handler can verify the payload, enqueue processing, and return quickly.

Polling still has an important role. Agents and CI systems need a fallback when webhook delivery is delayed, the test runner starts after the webhook fires, or a local development environment cannot receive inbound HTTP callbacks. A bounded polling API gives you deterministic waits without fixed sleeps.

A robust pattern is webhook-first with polling fallback. The agent calls a wait_for_email tool with an inbox ID, expected intent, and deadline. Behind the scenes, the tool checks for a webhook-delivered result first, then polls with a cursor or seen-message set until the deadline expires.

This keeps the agent interface simple while preserving operational reliability.

Do not give the model more email than it needs

LLM agents are powerful because they can reason across context. They are risky for the same reason. If you put a full inbound email into the prompt, every sender becomes a potential prompt author.

A safer design is to create two views of the same message. The engineering view contains full JSON, raw references, headers, bodies, and debug details. The agent view contains only the minimal task result.

For a verification flow, the agent view might include the OTP and the fact that it matched the expected inbox. For a support intake flow, it might include a sanitized summary and classification label. For a procurement workflow, it might include extracted fields that still require human or policy approval.

This pattern also helps teams building larger AI production systems. Email ingestion is only one boundary in an agent stack. If your organization coordinates multiple models, teams, and workflows, an operating layer such as Virtuall’s operating layer for creative AI can sit alongside API inbox infrastructure to help govern broader AI production.

Security checks before an agent acts on email

Receiving structured JSON emails is the foundation, but safety comes from the checks you apply around that JSON. In production, treat every inbound message as hostile until proven otherwise.

Good defaults include:

  • Verify signed webhook payloads before parsing or processing the body.
  • Dedupe by delivery ID, message ID, and artifact hash so retries do not trigger repeated actions.
  • Prefer text/plain for extraction when possible, and avoid rendering untrusted HTML.
  • Validate links against expected domains before a browser, agent, or backend fetches them.
  • Use allowlists for actions that can spend money, change credentials, or submit forms.
  • Log stable IDs and parser decisions, not unnecessary secrets or full message bodies.
  • Apply consume-once semantics to OTPs, magic links, and confirmation URLs.

The principle is simple: the email can inform automation, but it should not directly command automation.

Where Mailhook fits

Mailhook is built for teams that need programmable temp inboxes for agents, QA automation, and verification flows. Instead of logging into a mailbox or scraping a UI, you create disposable inboxes via API and receive inbound messages as structured JSON.

For safer agent automation, Mailhook provides the primitives this architecture depends on:

  • Disposable inbox creation via RESTful API.
  • Structured JSON email output for machine consumption.
  • Real-time webhook notifications for low-latency delivery.
  • Polling API support for fallback and local workflows.
  • Instant shared domains for fast setup.
  • Custom domain support when you need domain control.
  • Signed payloads for webhook authenticity checks.
  • Batch email processing for higher-volume workflows.

The exact integration contract is documented in Mailhook’s llms.txt, which is the best reference for agent and tool builders that need machine-readable implementation details.

Mailhook is a fit when your workflow needs an email address that is not a human account, an inbox that can be created programmatically, and a message format that automation can process without brittle HTML scraping. You can also get started without a credit card.

A practical tool contract for LLM agents

A safe agent tool should expose intent-level operations rather than low-level mailbox behavior. Instead of giving the model a generic “read inbox” tool, expose a narrow tool that knows what success looks like.

For example:

type WaitForVerificationEmailInput = {
  inbox_id: string;
  expected_sender_domain: string;
  artifact_type: "otp" | "magic_link";
  deadline_ms: number;
};

type WaitForVerificationEmailResult = {
  status: "matched" | "timeout" | "ambiguous";
  artifact?: string;
  delivery_id?: string;
  message_id?: string;
  reason?: string;
};

This contract prevents the agent from browsing arbitrary messages, choosing between unrelated emails, or deciding whether a suspicious link is acceptable. The tool can enforce the rules in code and return ambiguous when more than one candidate matches.

That last state is important. Safe automation should fail closed. If two messages match, if the sender is unexpected, or if the URL does not pass validation, the tool should stop the agent and surface a reason.

Common mistakes when receiving email in agent workflows

The biggest mistake is reusing one inbox across many attempts. Shared inboxes create races, stale matches, and duplicate actions. A disposable inbox per attempt gives your system a clean correlation boundary.

Another common mistake is relying on fixed sleeps. Email delivery is asynchronous. A 10-second sleep might pass locally and fail in CI. A deadline-based wait using webhooks and polling is more reliable and easier to debug.

A third mistake is letting the LLM parse raw email content. Models are not deterministic parsers, and email is not trusted input. Use code to extract artifacts, then give the model the result.

Finally, teams often forget idempotency. Webhooks may be retried, polling may see the same message twice, and senders may resend verification emails. Your system should be able to process the same delivery more than once without repeating the external action.

Implementation checklist

Area Safer default Why it matters
Inbox scope One disposable inbox per attempt Prevents stale messages and parallel races
Delivery Webhook-first, polling fallback Balances low latency with deterministic recovery
Parsing Normalize to JSON before agent exposure Removes mailbox UI and HTML scraping from the loop
Agent view Minimal artifact plus evidence IDs Reduces prompt injection and accidental disclosure
Security Verify signatures and validate URLs Blocks spoofed webhooks and unsafe actions
Dedupe Delivery, message, and artifact keys Makes retries safe
Observability Log IDs, timestamps, and match reasons Speeds up debugging without over-logging content

If you can enforce these defaults, receiving emails as JSON becomes more than a convenience. It becomes a safety control for agentic systems.

Frequently Asked Questions

Does receiving emails as JSON make email safe for AI agents? Not by itself. JSON makes email easier to validate, dedupe, filter, and minimize before it reaches an agent. You still need signature verification, link validation, idempotency, and constrained tool design.

Should an LLM agent ever see the full email body? Usually no. For verification and QA flows, the agent should see only the extracted artifact and a small amount of evidence. Keep raw bodies and HTML in engineering logs or storage, not in the model prompt.

Are webhooks better than polling for email automation? Webhooks are usually better for real-time delivery and scale. Polling is useful as a fallback, for local development, and for deterministic waits when the consumer cannot receive webhooks.

What is the safest way to handle OTP emails? Create a disposable inbox for the attempt, wait with a deadline, match by expected sender and context, extract the OTP with deterministic code, then consume it once. Do not ask the model to choose the code from raw email text.

Can Mailhook be used with custom domains? Yes. Mailhook supports instant shared domains for fast setup and custom domain support when you need more control over routing, allowlisting, or environment separation.

Start with a JSON-first inbox boundary

If your agent workflow depends on email, the inbox is part of your security boundary. Treat it like an API, not a browser tab.

With Mailhook, you can create disposable inboxes via API, receive emails as structured JSON, use real-time webhooks or polling, and verify signed payloads before automation acts. For exact integration details, use the canonical Mailhook llms.txt reference and build your email tools around small, deterministic, agent-safe results.

Related Articles