Why use WebSockets?
| Feature | Webhook | WebSocket |
|---|---|---|
| Setup | Requires public URL + ngrok | No external tools needed |
| Connection | HTTP request per event | Persistent connection |
| Direction | OpenMail → Your server | Bidirectional |
| Firewall | Must expose port | Outbound only |
| Latency | HTTP round-trip | Instant streaming |
Connecting
Authenticate with your API key via theAuthorization header or token query parameter.
?token= query parameter is useful for browser clients and CLI tools that can’t set custom headers on WebSocket connections.
Subscribe
After connecting, send asubscribe message to start receiving events. You can subscribe to specific inboxes, specific event types, or both.
Subscribe to all inboxes and all events
Subscribe to specific inboxes
Subscribe to specific event types
subscribed confirmation:
inbox_ids is empty in the response, you are subscribed to all inboxes on your account. Otherwise it lists the specific inboxes you’re subscribed to.
Subscriptions accumulate - sending multiple subscribe messages adds to your existing subscriptions.
When subscribing to specific
inbox_ids, OpenMail verifies you own each inbox. Unowned inbox IDs return an error.Receiving events
Events arrive as JSON messages on the WebSocket. The payload is identical to the webhook event payload.Event types
| Event | Description |
|---|---|
message.received | A new inbound email was delivered to an inbox |
Full examples
Unsubscribe
Remove subscriptions without disconnecting.Unsubscribe from specific inboxes
Unsubscribe from everything
subscribe message.
Protocol reference
Client → Server
| Message | Fields | Description |
|---|---|---|
subscribe | inbox_ids?, event_types? | Subscribe to events. Omit both to get all events for all inboxes. |
unsubscribe | inbox_ids? | Remove subscriptions. Empty = unsubscribe from all. |
ack | event_id | Acknowledge receipt of an event (reserved for future replay). |
ping | Application-level keepalive. |
Server → Client
| Message | Fields | Description |
|---|---|---|
subscribed | inbox_ids | Subscription confirmed. Empty array = all inboxes. |
unsubscribed | inbox_ids | Unsubscription confirmed. |
error | message | Error details (invalid JSON, unknown type, unauthorized inbox). |
pong | Response to ping. | |
| (event) | Same as webhook payload | Email event pushed in real-time. |
Delivery semantics
When a customer has both an active WebSocket connection and a webhook URL configured, OpenMail prefers the WebSocket. If the WebSocket is down, events fall back to the webhook with the same retry policy.| Scenario | Delivery method |
|---|---|
| WebSocket connected + subscribed | WebSocket (instant) |
| WebSocket disconnected, webhook URL set | Webhook (with retries) |
| Neither | Event stored, marked as failed after retries |
Connection management
- Heartbeat - The server sends WebSocket pings every 30 seconds. Connections that don’t respond with a pong within 10 seconds are terminated.
- Reconnection - Implement client-side reconnection with exponential backoff. The Python
websocketslibrary handles this automatically withasync for ws in websockets.connect(...). - Multiple connections - You can open multiple WebSocket connections per account. Events are delivered to all connections whose subscriptions match.
Comparison with webhooks
Use WebSockets when:- Your agent runs locally or behind a firewall
- You want instant delivery with no round-trip latency
- You don’t want to manage a public HTTPS endpoint
- Your server is already publicly accessible
- You need guaranteed delivery with automatic retries
- You prefer stateless, request-based integration