Receiving Email
Inbound email processing with webhooks and polling for agent mailboxes.
How Inbound Works
When someone sends an email to your agent's mailbox address, Transactional receives the message and makes it available in two ways:
- Webhooks (recommended) — Real-time HTTP POST to your endpoint
- Polling — Query the inbox API on a schedule
Inbound emails are available via API in under 2 seconds after receipt.
Webhook Delivery
Set up a webhook to receive real-time notifications when new emails arrive.
// Register a webhook
await tx.agentEmail.webhooks.create({
mailbox: mailbox.id,
url: 'https://yourapp.com/webhooks/agent-email',
events: ['message.received'],
});Your endpoint receives a POST request with the full message:
// Express/Hono webhook handler
app.post('/webhooks/agent-email', async (req, res) => {
const event = req.body;
if (event.type === 'message.received') {
const message = event.data;
console.log(`New email from ${message.from}`);
console.log(`Subject: ${message.subject}`);
console.log(`Body: ${message.textBody}`);
// Process with your agent
await agent.processIncomingEmail(message);
}
res.status(200).send('OK');
});See Webhooks for HMAC verification and all event types.
Polling
Query the inbox API to check for new messages. Useful for batch processing or environments where webhooks are not practical.
// Poll for unread messages
const messages = await tx.agentEmail.inbox.list({
mailbox: mailbox.id,
unread: true,
sort: 'received_at:desc',
limit: 20,
});
for (const message of messages.data) {
await agent.processIncomingEmail(message);
// Mark as read after processing
await tx.agentEmail.inbox.markRead(message.id);
}Webhooks vs Polling
| Webhooks | Polling | |
|---|---|---|
| Latency | Real-time (under 2s) | Depends on interval |
| Complexity | Requires public endpoint | Simple API calls |
| Reliability | Automatic retries | You control retry logic |
| Best for | Conversational agents | Batch processing, cron jobs |
Inbound Parsing
Transactional parses inbound emails and extracts:
| Field | Description |
|---|---|
from | Sender address |
to | Recipient address(es) |
cc | CC addresses |
subject | Email subject |
htmlBody | HTML content |
textBody | Plain text content |
headers | All email headers |
attachments | File attachments with download URLs |
threadId | Thread ID (if part of a conversation) |
inReplyTo | Message ID this is replying to |
receivedAt | Timestamp of receipt |
Attachment Handling
Inbound attachments are stored and accessible via download URL.
const message = await tx.agentEmail.inbox.get(messageId);
for (const attachment of message.attachments) {
console.log(`File: ${attachment.filename}`);
console.log(`Size: ${attachment.size} bytes`);
console.log(`Type: ${attachment.contentType}`);
// Download the attachment
const response = await fetch(attachment.downloadUrl);
const buffer = await response.arrayBuffer();
}Attachments are retained for 30 days after receipt.
Spam Filtering
Inbound messages are automatically scanned for spam. Messages flagged as spam are still delivered but include a spam score.
if (message.spamScore > 5.0) {
console.log('Likely spam, skipping');
await tx.agentEmail.inbox.archive(message.id);
return;
}Next Steps
- Inbox Management — Search, filter, and organize messages
- Thread Tracking — Manage conversation threads
- Webhooks — Complete webhook configuration