2026-04-05 · websocket webhooks architecture real-time email-api
WebSocket vs Webhooks for Agent Email: When to Use Each
Your agent needs to know when email arrives. There are two ways to get that signal: WebSockets (the agent holds a persistent connection and receives events in real time) or webhooks (the email service POSTs to your endpoint when something happens).
Both work. Both have tradeoffs. Here's when to use each — and why using both together is often the right answer.
WebSocket: Real-Time, Stateful
A WebSocket connection is a persistent, bidirectional channel between your agent and the email service. Once established, events are pushed to your agent the instant they occur.
How It Works
import WebSocket from "ws";
const ws = new WebSocket("wss://myagentmail.com/v1/ws", {
headers: { "X-API-Key": process.env.MYAGENTMAIL_API_KEY },
});
ws.on("open", () => {
console.log("Connected — listening for email events");
});
ws.on("message", (raw) => {
const event = JSON.parse(raw.toString());
switch (event.type) {
case "message.received":
handleInboundEmail(event.data);
break;
case "message.bounced":
handleBounce(event.data);
break;
case "message.delivered":
handleDeliveryConfirmation(event.data);
break;
}
});
ws.on("close", () => {
// Reconnect logic
setTimeout(connect, 1000);
});
Strengths
Latency. Events arrive in milliseconds. For time-sensitive workflows like 2FA code extraction, this is the difference between catching a 60-second expiration window and missing it.
No public URL required. Your agent initiates the connection outbound. It can run behind a NAT, on a laptop, in a container with no ingress — anywhere that can make an outbound TCP connection.
Inline processing. The event handler runs in the same process as your agent logic. No need for shared state, queues, or database coordination between "the thing that receives email" and "the thing that acts on it."
Bidirectional. You can send subscription filters over the same connection — listen only to specific inboxes, specific event types, or specific senders.
Weaknesses
Connection management. WebSocket connections drop. Networks blip. Servers restart. You need reconnection logic with exponential backoff, and you need to handle the gap — events that occurred while you were disconnected.
Statefulness. The connection is tied to a running process. If your agent crashes, the connection dies and events are missed until reconnection. There's no built-in durability.
Scaling is harder. If you're running multiple instances of your agent behind a load balancer, each instance has its own WebSocket connection. You need to coordinate which instance handles which events.
Webhooks: Durable, Stateless
Webhooks invert the model. Instead of your agent maintaining a connection, the email service sends an HTTP POST to your endpoint when an event occurs.
How It Works
// Express.js webhook handler
import express from "express";
import crypto from "crypto";
const app = express();
app.post("/webhooks/email", express.json(), (req, res) => {
// Verify the webhook signature
const signature = req.headers["x-signature"];
const expected = crypto
.createHmac("sha256", process.env.WEBHOOK_SECRET)
.update(JSON.stringify(req.body))
.digest("hex");
if (signature !== expected) {
return res.status(401).send("Invalid signature");
}
const event = req.body;
switch (event.type) {
case "message.received":
handleInboundEmail(event.data);
break;
case "message.bounced":
handleBounce(event.data);
break;
}
// Acknowledge receipt immediately
res.status(200).send("OK");
});
app.listen(3000);
Register your webhook endpoint with myagentmail:
curl -X POST https://myagentmail.com/v1/webhooks \
-H "X-API-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-server.com/webhooks/email",
"events": ["message.received", "message.bounced"],
"secret": "your-webhook-secret"
}'
Strengths
Durability. If your server is down when an event occurs, the email service retries. Most providers retry with exponential backoff for hours or days. Events aren't lost just because your process was temporarily unavailable.
Statelessness. Each webhook delivery is an independent HTTP request. Your server doesn't need to maintain any persistent connection. It can scale horizontally behind a load balancer without coordination.
Simple deployment model. Any HTTP server can receive webhooks. No WebSocket libraries, no connection management, no reconnection logic.
Auditability. Each webhook delivery is a discrete HTTP request with a timestamp, a payload, and a response code. Easy to log, replay, and debug.
Weaknesses
Latency. Webhook delivery typically adds 1-10 seconds of latency compared to WebSocket. The email service batches events, makes an HTTP request to your server, waits for a response, and retries on failure. For most workflows this is fine. For time-sensitive flows (2FA, real-time conversations), it's too slow.
Public URL required. Your server must be reachable from the internet. This means a deployed server with a public IP or domain, proper TLS, and firewall rules. Local development requires a tunnel (ngrok, cloudflared).
Security surface. An exposed webhook endpoint is an attack vector. You must validate signatures on every request, handle replay attacks, and rate-limit incoming requests.
Ordering is not guaranteed. Webhooks can arrive out of order, especially with retries. If your agent depends on processing events in sequence, you need to handle reordering.
Decision Matrix
| Factor | WebSocket | Webhook |
|---|---|---|
| Latency | Milliseconds | 1-10 seconds |
| Durability | Events lost during disconnection | Retried on failure |
| Public URL needed | No | Yes |
| Scaling | Requires coordination | Stateless, easy |
| Infrastructure | Minimal (outbound TCP) | HTTP server + TLS |
| Best for | Real-time agent workflows | Background processing |
The Best Pattern: Use Both
For production agent systems, the most robust architecture uses both delivery mechanisms:
WebSocket for real-time processing. Your agent maintains a WebSocket connection for immediate event handling. Interactive workflows — conversations, 2FA, live monitoring — go through this path.
Webhook as a durable fallback. A webhook endpoint catches events that the agent missed during WebSocket disconnection. On reconnection, the agent checks the webhook log for any events it didn't process.
class EmailEventHandler {
private processedEvents = new Set<string>();
async handleEvent(event: EmailEvent, source: "websocket" | "webhook") {
// Deduplicate across both sources
if (this.processedEvents.has(event.id)) return;
this.processedEvents.add(event.id);
// Process the event
await this.processEmail(event);
}
}
The WebSocket gives you speed. The webhook gives you durability. Together, they give you both — no missed events, no unnecessary latency.
Recommendations by Use Case
Conversational agent (support, sales, scheduling): WebSocket primary, webhook fallback. The agent needs to respond quickly to maintain natural conversation pacing.
Background processing (lead scoring, analytics, archiving): Webhook only. Latency doesn't matter and you want the simplest infrastructure.
2FA and verification flows: WebSocket only. You need sub-second delivery and the flow is inherently synchronous.
Multi-tenant platform: Webhook primary with WebSocket available per tenant. Webhooks scale more naturally across many tenants; individual tenants can upgrade to WebSocket for real-time features.
The choice isn't binary. Understand the tradeoffs, pick the primary mechanism that matches your latency and infrastructure requirements, and consider adding the other as a complement for robustness.