Architecture guide

Inbox polling vs webhooks: choose by failure behavior.

Latency is only the visible difference. The real choice is who owns waiting, retries, duplicate delivery, authentication, recovery, and the state that connects an email to an active task.

By Evidence checked 11 min read Editorial method

Direct answer

Use bounded polling or a provider-supported wait operation for short-lived CLI, CI, and browser tasks that already have an active process and need one message. Use webhooks for persistent services that must react to many asynchronous messages without keeping workers open. Keep idempotent processing and a reconciliation query in either design. A webhook can be delayed or delivered more than once; polling can miss filters, hit rate limits, or stop before delayed mail arrives. The most reliable production design often uses webhooks for fast notification and mailbox queries for recovery.

Visual guide

A resilient hybrid event path

The event makes the system fast; durable mailbox state makes it recoverable.

  1. 01
    Ingest once

    Store the message and assign a stable identifier before notifying consumers.

  2. 02
    Notify quickly

    Deliver a signed webhook or event containing bounded metadata.

  3. 03
    Process idempotently

    Queue work and reject repeated state transitions for the same event.

  4. 04
    Reconcile gaps

    Query messages after the last stored cursor when delivery is uncertain.

Decision rule

Start with the lifetime of the caller

A Playwright test has a live process, a known trigger, and a deadline. It can wait for one matching message and stop. Adding a public webhook endpoint, queue, correlation store, and cleanup job may create more failure modes than it removes. A bounded wait operation or polling loop is usually the smaller design.

A support agent service or workflow engine may run for months and receive messages when no initiating process is alive. Polling every mailbox from every worker wastes requests and complicates concurrency. A verified webhook that writes to a durable queue is a better notification mechanism, as long as the mailbox or event store remains available for recovery.

The choice should follow process lifetime and workload shape, not a blanket claim that webhooks are modern or polling is simple. Both require explicit state.

WorkloadPreferred starting pointReason
One OTP in a browser testBounded wait or pollingThe caller is active and knows the recipient and trigger time
Many long-lived agent inboxesWebhook plus queueMessages arrive independently of request sessions
Local CLI task behind NATPollingNo public callback endpoint is required
Workflow with strict recovery needWebhook plus reconciliationFast reaction and durable catch-up both matter
Polling design

Poll with a cursor, exact filters, backoff, and a deadline

Record the trigger time before the external action. Query the intended mailbox and direction for messages received afterward, with sender or subject context where reliable. Keep the page size small. If there is no match, back off with jitter and continue until the deadline. If there are several valid candidates, return ambiguity instead of choosing the newest globally.

A dedicated wait-for-code operation can package these rules and return a narrow result. The caller should still assert that the code or link changed the outside application state. Receipt and extraction are intermediate evidence.

Persist a cursor or last processed message ID when polling a long-lived mailbox. Without one, a restart can reprocess old mail or require repeatedly scanning the whole history. Use provider timestamps carefully because delivery order and original sent time can differ.

  • Cap attempts and total elapsed time.
  • Honor rate-limit responses and server retry guidance.
  • Add jitter so parallel jobs do not synchronize requests.
  • Report no message, ambiguous match, parse failure, and timeout separately.
Webhook design

Acknowledge quickly and move work into a durable consumer

The public endpoint should verify the signature or provider authentication, validate basic envelope shape, store or enqueue the event, and respond quickly. It should not run a long model call, download every attachment, or perform a fragile external action before acknowledgement. Slow handlers increase retries and duplicate work.

Use a stable event or message identifier as the idempotency key. The first consumer transition can claim the event; later deliveries should observe the recorded state and stop. If the provider does not supply a reliable identifier, derive a bounded fingerprint from mailbox, message headers, and payload metadata while retaining the original event for diagnosis.

A valid webhook proves that the event came through the expected transport path. It does not make the email body, links, or requested action trustworthy. Apply workflow eligibility and content policy after transport verification.

  1. 01

    Verify transport

    Check signature, timestamp tolerance, route, and expected event type.

  2. 02

    Persist before work

    Write an event record or queue message before acknowledging.

  3. 03

    Claim idempotently

    Allow one consumer to advance the workflow for the event.

  4. 04

    Apply content policy

    Validate sender context, links, files, and action authority.

Hybrid recovery

Use notification for speed and mailbox state for truth

Webhooks can fail because DNS, certificates, signatures, deploys, queues, or handlers fail. Polling can fail because a process ends, a filter is wrong, or rate limits intervene. A hybrid design treats the webhook as a prompt to inspect durable mailbox state, not as the only copy of the message.

Store the last reconciled cursor per mailbox or workflow. On startup and on a schedule, query messages after that cursor and enqueue anything not already processed. The same idempotent consumer handles webhook and reconciliation events. This prevents two separate business paths from drifting.

Fast path

Webhook notification

React quickly when the provider can reach the service.

Truth

Durable mailbox query

Retrieve current message state under scoped authorization.

Repair

Cursor reconciliation

Recover events after downtime without replaying the entire inbox.

Operations

Measure latency and loss at each boundary

Record message ingestion time, notification attempt, endpoint acknowledgement, queue availability, consumer start, business transition, and final application outcome. A single end-to-end latency number cannot tell the team whether transport, notification, queueing, model work, or the external system caused the delay.

Alert on a rising webhook retry rate, reconciliation gaps, old unprocessed messages, repeated ambiguity, and polling rate limits. Keep bodies, OTPs, addresses, and secrets out of broad telemetry. Use message and workflow identifiers that operators can resolve through restricted tools when investigation is necessary.

MetricMeaningUseful response
Ingest to notifyProvider or internal event delayInspect event production and routing
Notify to acknowledgeEndpoint availability and loadInspect signature and queue path
Acknowledge to processQueue and worker delayScale or repair consumer
Process to outcomeApplication or external action delayInspect workflow state and policy
Implementation judgment

Optimize for recoverable state, then for speed

Use the simplest wait mechanism that fits the caller lifetime. For persistent systems, send verified notifications into an idempotent queue and keep a mailbox cursor for repair. This design remains understandable when messages are delayed, delivered twice, or arrive while the service is down.

Evidence

Sources and product scope

Product behavior is verified against the mails0 source and documentation. External comparisons link to official vendor documentation checked on 2026-08-15.

Questions and answers

Questions that come up in practice

Are webhooks always better than polling for email?

No. A bounded CLI, CI, or browser task often benefits from polling or a wait operation. Persistent services with many asynchronous inboxes usually benefit from webhooks plus durable processing.

How often should an email inbox be polled?

Use provider guidance, exponential backoff with jitter, a small result limit, and a total deadline. Avoid a fixed aggressive interval across many parallel workers.

What happens if a webhook is missed?

Keep durable message state and reconcile from a stored cursor. Feed recovered messages through the same idempotent consumer used by webhook events.

Start with a bounded inbox

Prove the smallest useful email loop.

Start with one scoped inbox and one expected message. Add durable identity, sending, and operational complexity only when the first loop works.