WebSocket (Coming Soon)
Real-time bidirectional communication
WebSocket (Coming Soon)
Info
Status: Planned for Sprint 4 (Q3 2026). WebSocket support is not yet available but represents the next evolution of real-time communication in daimon.email.
WebSocket connections will provide real-time, bidirectional communication between your agents and daimon.email, offering lower latency and more efficient resource usage than webhooks or polling.
Why WebSockets?
Lower Latency
Sub-10ms event delivery vs 100-500ms for webhooks. Perfect for conversational agents.
Bidirectional
Agents can send commands and receive events over the same connection.
Less Overhead
No HTTP handshake per event. Single persistent connection uses fewer resources.
No Public Endpoint
Agents don't need a publicly accessible webhook URL. Works behind NAT/firewalls.
Comparison: Polling vs Webhooks vs WebSockets
| Feature | Polling | Webhooks | WebSockets |
|---|---|---|---|
| Latency | 5-60 seconds | 100-500ms | <10ms |
| Resource usage | High (constant API calls) | Low | Very low |
| Public endpoint required | No | Yes (HTTPS) | No |
| Complexity | Low | Medium | Medium |
| Reliability | High | Medium (retries) | High |
| Best for | Simple agents, low-traffic | Production agents | Conversational AI, high-traffic |
How WebSockets Will Work
Establish connection
Connect to the WebSocket endpoint with authentication:
import WebSocket from 'ws';
const ws = new WebSocket('wss://ws.daimon.email/v1/stream', {
headers: {
'Authorization': `Bearer ${inboxApiKey}`
}
});
ws.on('open', () => {
console.log('Connected to daimon.email WebSocket');
});Receive events in real-time
Listen for events as they happen:
ws.on('message', (data) => {
const event = JSON.parse(data.toString());
if (event.type === 'message.received') {
console.log('New message:', event.payload.message.subject);
// Process the message immediately
}
});Send commands
Send commands over the same connection:
// Mark message as read
ws.send(JSON.stringify({
action: 'mark_as_read',
message_id: 'msg_abc123'
}));
// Send an email
ws.send(JSON.stringify({
action: 'send_email',
inbox_id: 'inbox_abc123',
to: 'user@example.com',
subject: 'Hello',
body: 'Message from agent'
}));Handle connection lifecycle
Implement reconnection logic for reliability:
ws.on('close', (code, reason) => {
console.log(`WebSocket closed: ${code} ${reason}`);
// Reconnect after 5 seconds
setTimeout(() => connectWebSocket(), 5000);
});
ws.on('error', (error) => {
console.error('WebSocket error:', error);
});Planned Features
Event Streaming
Receive all webhook events via WebSocket:
ws.on('message', (data) => {
const event = JSON.parse(data.toString());
switch (event.type) {
case 'message.received':
handleNewMessage(event.payload.message);
break;
case 'message.bounced':
handleBounce(event.payload);
break;
case 'message.complaint':
handleComplaint(event.payload);
break;
case 'account.upgraded':
handleUpgrade(event.payload);
break;
}
});Command Execution
Execute API commands over WebSocket instead of HTTP:
// Send email
ws.send(JSON.stringify({
action: 'send_email',
inbox_id: 'inbox_abc123',
params: {
to: 'user@example.com',
subject: 'Hello',
body: 'Message from agent'
}
}));
// Listen for response
ws.on('message', (data) => {
const response = JSON.parse(data.toString());
if (response.request_id === 'send_email_123') {
console.log('Email sent:', response.result.message_id);
}
});Multiplexing (Multiple Inboxes)
Subscribe to events from multiple inboxes over a single WebSocket connection:
// Subscribe to multiple inboxes
ws.send(JSON.stringify({
action: 'subscribe',
inbox_ids: ['inbox_abc123', 'inbox_def456', 'inbox_ghi789']
}));
// Receive events from all subscribed inboxes
ws.on('message', (data) => {
const event = JSON.parse(data.toString());
console.log(`Event from ${event.inbox_id}: ${event.type}`);
});Ping/Pong Heartbeats
Keep connections alive with automatic heartbeats:
// Server sends ping every 30 seconds
ws.on('ping', () => {
ws.pong(); // Client responds with pong
});
// Client can also send pings
setInterval(() => {
ws.ping();
}, 30000);Backpressure Handling
Handle slow consumers gracefully:
ws.on('message', async (data) => {
const event = JSON.parse(data.toString());
// Pause receiving events while processing
ws.pause();
await processEvent(event);
// Resume receiving events
ws.resume();
});Authentication
WebSocket authentication will support multiple methods:
1. Bearer Token (Recommended)
Use inbox or account API key in the connection header:
const ws = new WebSocket('wss://ws.daimon.email/v1/stream', {
headers: {
'Authorization': `Bearer ${apiKey}`
}
});2. Query Parameter
Pass API key as query parameter (less secure, use only if headers not supported):
const ws = new WebSocket(`wss://ws.daimon.email/v1/stream?key=${apiKey}`);3. Connection Token (Future)
Generate short-lived connection tokens for enhanced security:
curl -X POST https://api.daimon.email/v1/websocket/token \
-H "Authorization: Bearer dm_live_inbox123..."Response
{
"result": {
"token": "wst_abc123...",
"expires_at": "2026-03-16T11:00:00Z"
}
}const ws = new WebSocket('wss://ws.daimon.email/v1/stream', {
headers: {
'Authorization': `Bearer ${connectionToken}`
}
});Client Libraries
Official WebSocket client libraries will be provided:
TypeScript
import { DaimonWebSocket } from 'daimon-email';
const client = new DaimonWebSocket({
apiKey: inboxApiKey,
autoReconnect: true,
reconnectDelay: 5000
});
client.on('message.received', (message) => {
console.log('New message:', message.subject);
});
client.on('connected', () => {
console.log('WebSocket connected');
});
client.on('disconnected', (reason) => {
console.log('WebSocket disconnected:', reason);
});
await client.connect();Python
from daimon_email import DaimonWebSocket
client = DaimonWebSocket(
api_key=inbox_api_key,
auto_reconnect=True,
reconnect_delay=5
)
@client.on('message.received')
def handle_message(message):
print(f"New message: {message.subject}")
@client.on('connected')
def handle_connected():
print('WebSocket connected')
@client.on('disconnected')
def handle_disconnected(reason):
print(f"WebSocket disconnected: {reason}")
await client.connect()Go
package main
import (
"github.com/daimon-email/go-sdk/websocket"
)
func main() {
client := websocket.New(websocket.Config{
APIKey: inboxAPIKey,
AutoReconnect: true,
ReconnectDelay: 5 * time.Second,
})
client.OnMessageReceived(func(msg *websocket.Message) {
fmt.Printf("New message: %s\n", msg.Subject)
})
client.OnConnected(func() {
fmt.Println("WebSocket connected")
})
client.OnDisconnected(func(reason string) {
fmt.Printf("WebSocket disconnected: %s\n", reason)
})
client.Connect()
}Use Cases
Conversational AI Agent
Real-time email conversation handling:
const ws = new DaimonWebSocket({ apiKey: inboxApiKey });
ws.on('message.received', async (message) => {
console.log(`New email from ${message.from}: ${message.subject}`);
// Generate AI response
const response = await generateResponse(message.body);
// Send reply immediately (no HTTP round-trip)
await ws.send({
action: 'send_email',
inbox_id: message.inbox_id,
to: message.from,
subject: `Re: ${message.subject}`,
body: response,
in_reply_to: message.message_id
});
console.log('Reply sent');
});
await ws.connect();Latency comparison:
- Polling: 5-60 seconds (depending on poll interval)
- Webhooks: 100-500ms (HTTP overhead + processing)
- WebSocket:
<10ms(instant)
Multi-Agent Dashboard
Monitor multiple agents from a single connection:
const ws = new DaimonWebSocket({ apiKey: accountApiKey });
// Subscribe to all inboxes
ws.send({
action: 'subscribe',
inbox_ids: ['inbox_1', 'inbox_2', 'inbox_3', 'inbox_4']
});
ws.on('message.received', (message) => {
// Update dashboard in real-time
updateDashboard(message.inbox_id, message);
});
ws.on('message.bounced', (bounce) => {
// Show alert for bounced emails
showAlert(`Bounce: ${bounce.recipient}`);
});
await ws.connect();Email Notification System
Real-time notifications for critical emails:
const ws = new DaimonWebSocket({ apiKey: inboxApiKey });
ws.on('message.received', (message) => {
// Check if email is urgent
if (message.subject.includes('[URGENT]') || message.labels.includes('priority')) {
// Send push notification to operator
sendPushNotification({
title: 'Urgent Email',
body: `From: ${message.from} - ${message.subject}`
});
}
});
await ws.connect();Migration Path
We'll support a gradual migration from webhooks to WebSockets:
Hybrid mode (recommended for transition)
Use both webhooks and WebSockets during migration:
// Keep existing webhook for reliability
// Add WebSocket for low-latency events
const ws = new DaimonWebSocket({ apiKey: inboxApiKey });
ws.on('message.received', (message) => {
// Fast path: process via WebSocket
processMessage(message);
});
// Webhook still processes events if WebSocket is down
app.post('/webhook', (req, res) => {
const event = req.body;
// Check if already processed via WebSocket
if (!isProcessed(event.event_id)) {
processMessage(event.message);
}
res.status(200).send('OK');
});WebSocket-only mode
Once stable, disable webhooks and use WebSocket exclusively:
const ws = new DaimonWebSocket({
apiKey: inboxApiKey,
autoReconnect: true,
reconnectDelay: 5000
});
ws.on('message.received', async (message) => {
await processMessage(message);
});
await ws.connect();Frequently Asked Questions
When will WebSockets be available?
Sprint 4 (Q3 2026). We'll announce the exact release date via email and status.daimon.email.
Will webhooks still be supported?
Yes. Webhooks will remain fully supported. WebSockets are an additional option, not a replacement.
Can I use both webhooks and WebSockets?
Yes. You can use both simultaneously during migration or for redundancy.
What happens if my WebSocket disconnects?
- Auto-reconnect: Client libraries will automatically reconnect
- Event replay: On reconnect, you'll receive missed events (up to 5 minutes)
- Fallback: Use webhooks as a backup delivery mechanism
Are WebSockets available on all tiers?
Yes. WebSockets will be available on all tiers (free, developer, growth, enterprise).
How many WebSocket connections can I have?
- Free tier: 1 connection
- Developer tier: 10 connections
- Growth tier: 100 connections
- Enterprise tier: Unlimited
Can agents behind NAT/firewalls use WebSockets?
Yes. WebSockets work behind NAT/firewalls because the agent initiates the outbound connection. No public endpoint required.
Get Notified
Want to be notified when WebSocket support launches?
Join the Waitlist
Sign up for early access and beta testing opportunities