IMAP & SMTP
Traditional email protocol access for paid tiers
Overview
While daimon.email's REST API is optimized for AI agents, some use cases require traditional email protocols:
- SMTP (sending) - For agents that use existing email libraries or need direct SMTP access
- IMAP (receiving) - For agents that poll mailboxes or use email clients (planned, not yet available)
This guide explains how to access your daimon.email inboxes via standard email protocols.
Info
SMTP and IMAP access are paid tier features. Free tier accounts can only use the REST API.
SMTP (Outbound Email)
Availability
| Tier | SMTP Access | Credentials |
|---|---|---|
| Free | ❌ Disabled | N/A |
| Starter | ✅ Enabled | Per-account |
| Pro | ✅ Enabled | Per-account |
| Enterprise | ✅ Enabled | Per-account + dedicated IPs |
Getting SMTP Credentials
import { DaimonClient } from '@daimon/sdk';
const client = new DaimonClient({ apiKey: process.env.DAIMON_API_KEY });
// Get SMTP credentials for your account
const smtp = await client.account.getSmtp();
console.log(smtp);
// {
// host: "smtp.daimon.email",
// port: 587,
// username: "dm_live_3kL9xYw2qRn4",
// password: "smtp_secret_9kL2xYw1pQm3zBc5",
// tls: true,
// auth_method: "PLAIN"
// }from daimon import DaimonClient
client = DaimonClient(api_key=os.environ['DAIMON_API_KEY'])
# Get SMTP credentials
smtp = client.account.get_smtp()
print(smtp)
# {
# 'host': 'smtp.daimon.email',
# 'port': 587,
# 'username': 'dm_live_3kL9xYw2qRn4',
# 'password': 'smtp_secret_9kL2xYw1pQm3zBc5',
# 'tls': True,
# 'auth_method': 'PLAIN'
# }curl https://api.daimon.email/v1/account/smtp \
-H "Authorization: Bearer dm_live_..."
# Response:
# {
# "host": "smtp.daimon.email",
# "port": 587,
# "username": "dm_live_3kL9xYw2qRn4",
# "password": "smtp_secret_9kL2xYw1pQm3zBc5",
# "tls": true,
# "auth_method": "PLAIN"
# }Note
SMTP credentials are account-scoped, not inbox-scoped. Use the From: header to specify which inbox sends the email.
Sending via SMTP
Use your preferred SMTP library with the credentials:
import nodemailer from 'nodemailer';
// Get SMTP creds from daimon.email
const smtp = await client.account.getSmtp();
// Create nodemailer transport
const transporter = nodemailer.createTransport({
host: smtp.host,
port: smtp.port,
secure: false, // Use STARTTLS
auth: {
user: smtp.username,
pass: smtp.password,
},
});
// Send email
const info = await transporter.sendMail({
from: 'agent-abc123@daimon.email', // Your inbox address
to: 'recipient@company.com',
subject: 'Hello from SMTP',
text: 'This email was sent via SMTP protocol',
html: '<p>This email was sent via <strong>SMTP</strong> protocol</p>',
});
console.log('Message sent: %s', info.messageId);import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
# Get SMTP creds from daimon.email
smtp = client.account.get_smtp()
# Create message
msg = MIMEMultipart('alternative')
msg['Subject'] = 'Hello from SMTP'
msg['From'] = 'agent-abc123@daimon.email' # Your inbox address
msg['To'] = 'recipient@company.com'
text = 'This email was sent via SMTP protocol'
html = '<p>This email was sent via <strong>SMTP</strong> protocol</p>'
msg.attach(MIMEText(text, 'plain'))
msg.attach(MIMEText(html, 'html'))
# Send via SMTP
with smtplib.SMTP(smtp['host'], smtp['port']) as server:
server.starttls()
server.login(smtp['username'], smtp['password'])
server.send_message(msg)
print('Message sent via SMTP')package main
import (
"crypto/tls"
"fmt"
"net/smtp"
)
func main() {
// SMTP credentials from daimon.email API
host := "smtp.daimon.email"
port := "587"
username := "dm_live_3kL9xYw2qRn4"
password := "smtp_secret_9kL2xYw1pQm3zBc5"
from := "agent-abc123@daimon.email"
to := []string{"recipient@company.com"}
subject := "Hello from SMTP"
body := "This email was sent via SMTP protocol"
msg := []byte(fmt.Sprintf("From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n%s",
from, to[0], subject, body))
auth := smtp.PlainAuth("", username, password, host)
tlsConfig := &tls.Config{
ServerName: host,
}
conn, err := tls.Dial("tcp", host+":"+port, tlsConfig)
if err != nil {
panic(err)
}
client, err := smtp.NewClient(conn, host)
if err != nil {
panic(err)
}
if err = client.Auth(auth); err != nil {
panic(err)
}
if err = client.Mail(from); err != nil {
panic(err)
}
if err = client.Rcpt(to[0]); err != nil {
panic(err)
}
w, err := client.Data()
if err != nil {
panic(err)
}
_, err = w.Write(msg)
if err != nil {
panic(err)
}
err = w.Close()
if err != nil {
panic(err)
}
client.Quit()
fmt.Println("Message sent via SMTP")
}SMTP Settings Reference
| Setting | Value | Notes |
|---|---|---|
| Host | smtp.daimon.email | Shared pool (Starter/Pro), dedicated IP (Enterprise) |
| Port | 587 (STARTTLS) or 465 (TLS) | Port 25 blocked to prevent spam |
| Security | STARTTLS or TLS | TLS/SSL encryption required |
| Auth Method | PLAIN | Username/password authentication |
| Username | Your API key (e.g., dm_live_...) | Account-level credential |
| Password | SMTP password from /v1/account/smtp | Rotates on demand |
| From Address | Any inbox you own (e.g., agent-abc@daimon.email) | Verified via account ownership |
Note
The From: address must be an inbox you own. Attempting to send from unauthorized addresses will result in 550 5.7.1 Sender address rejected: not owned by this account.
Rotating SMTP Credentials
For security, you can rotate SMTP passwords:
// Rotate SMTP password (invalidates old password)
const newCreds = await client.account.rotateSmtpPassword();
console.log('New SMTP password:', newCreds.password);
// Update your .env or secrets manager# Rotate SMTP password
new_creds = client.account.rotate_smtp_password()
print(f"New SMTP password: {new_creds['password']}")curl -X POST https://api.daimon.email/v1/account/smtp/rotate \
-H "Authorization: Bearer dm_live_..."
# Response:
# {
# "host": "smtp.daimon.email",
# "port": 587,
# "username": "dm_live_3kL9xYw2qRn4",
# "password": "smtp_secret_NEW_PASSWORD",
# "rotated_at": "2026-03-16T15:45:00Z"
# }IMAP (Inbound Email)
Note
IMAP support is planned for Sprint 2 but not yet available. This section describes the planned implementation.
Planned Availability
| Tier | IMAP Access | Credentials |
|---|---|---|
| Free | ❌ Disabled | N/A |
| Starter | ✅ Planned | Per-inbox |
| Pro | ✅ Planned | Per-inbox |
| Enterprise | ✅ Planned | Per-inbox |
Planned IMAP Implementation
When available, you'll access IMAP credentials per-inbox:
// Get IMAP credentials for specific inbox
const imap = await client.inboxes.getImap('inbox_abc123');
console.log(imap);
// {
// host: "imap.daimon.email",
// port: 993,
// username: "agent-abc123@daimon.email",
// password: "imap_secret_9kL2xYw1pQm3zBc5",
// tls: true,
// folders: {
// inbox: "INBOX",
// sent: "Sent",
// drafts: "Drafts"
// }
// }# Get IMAP credentials
imap = client.inboxes.get_imap(inbox_id='inbox_abc123')
print(imap)
# {
# 'host': 'imap.daimon.email',
# 'port': 993,
# 'username': 'agent-abc123@daimon.email',
# 'password': 'imap_secret_9kL2xYw1pQm3zBc5',
# 'tls': True,
# 'folders': {...}
# }Planned IMAP features:
- Read emails - Fetch messages via standard IMAP clients
- Search - Use IMAP search queries
- Folders - INBOX, Sent, Drafts, custom folders
- IDLE - Real-time push notifications for new mail
- Threading - Gmail-style conversation view via
X-GM-THRIDextension
When to Use SMTP/IMAP vs REST API
| Use Case | Recommended Approach | Why |
|---|---|---|
| AI agent sending email | REST API | Simpler, includes threading, webhooks, rate limit handling |
| AI agent receiving email | REST API + Webhooks | Real-time delivery, parsed fields (reply_body, cta_links) |
| Integrating legacy email tools | SMTP/IMAP | Compatibility with existing libraries |
| Email client (Thunderbird, Outlook) | IMAP (when available) | Standard protocol support |
| Sending bulk campaigns | REST API | Better rate limiting, analytics, bounce handling |
| Migrating existing SMTP code | SMTP | Drop-in replacement, minimal code changes |
Info
Best practice: Use REST API for new agent projects. Fall back to SMTP/IMAP only when integrating with existing tools or libraries that require protocol-level access.
REST API Advantages Over SMTP/IMAP
The REST API provides features not available via traditional protocols:
1. Automatic Reply Extraction
REST API responses include reply_body (clean reply text) and cta_links (extracted action URLs). SMTP/IMAP require manual parsing.
// REST API (automatic extraction)
const message = await client.inboxes.getMessage(inboxId, messageId);
console.log(message.reply_body); // "Sure, I'd be happy to help!"
console.log(message.cta_links); // ["https://verify.example.com/token=..."]
// IMAP (manual parsing required)
const raw = imapClient.fetch(messageId);
const parsed = parseEmail(raw); // You implement this
const replyBody = extractReply(parsed.body); // You implement this
const ctaLinks = findVerificationLinks(parsed.body); // You implement this2. Native Threading
REST API threads are first-class objects with metadata. IMAP threading requires parsing In-Reply-To and References headers manually.
// REST API (built-in threads)
const thread = await client.threads.get('thread_abc123');
console.log(thread.message_count); // 7
console.log(thread.participants); // ["user@example.com", "agent@daimon.email"]
// IMAP (manual reconstruction)
const messages = imapClient.search(['HEADER', 'In-Reply-To', originalMessageId]);
// ...complex logic to reconstruct thread...3. Webhooks
REST API delivers real-time events. IMAP requires polling or IDLE connections (which timeout and reconnect frequently).
// REST API (push-based)
app.post('/webhooks/daimon', (req, res) => {
if (req.body.type === 'message.received') {
handleNewMessage(req.body.data);
}
});
// IMAP (poll-based or IDLE)
setInterval(() => {
imapClient.search(['UNSEEN'], (err, results) => {
results.forEach(handleNewMessage);
});
}, 30000); // Poll every 30s4. Rate Limit Handling
REST API returns structured errors with upgrade links when limits are hit. SMTP rejects with cryptic SMTP codes.
// REST API (actionable error)
try {
await client.inboxes.send(inboxId, {...});
} catch (error) {
if (error.code === 'SEND_LIMIT_EXCEEDED') {
console.log('Upgrade to send more:', error.upgrade_context.operator_action_url);
}
}
// SMTP (generic error)
try {
transporter.sendMail({...});
} catch (error) {
console.log(error.message); // "550 5.7.1 Sending quota exceeded"
// No upgrade link, no structured context
}Monitoring SMTP Usage
Track SMTP sends via the account endpoint:
const account = await client.account.get();
console.log(account.sends_today); // 347
console.log(account.daily_send_limit); // 1000
console.log(account.smtp_enabled); // true
if (account.sends_today > account.daily_send_limit * 0.9) {
console.warn('Approaching daily send limit! Consider upgrading.');
}Security Best Practices
Rotate Credentials Regularly
Rotate SMTP passwords every 90 days or after team member offboarding.
Use TLS/STARTTLS
Never send SMTP credentials over unencrypted connections. Always use port 587 (STARTTLS) or 465 (TLS).
Restrict From Addresses
Only send from inboxes you own. Unauthorized addresses will be rejected.
Monitor for Abuse
Subscribe to account.smtp_abuse_detected webhooks to catch compromised credentials.
Error Codes
Common SMTP errors:
| SMTP Code | Meaning | Solution |
|---|---|---|
550 5.7.1 | Unauthorized sender address | Use an inbox you own in From: header |
550 5.7.26 | Daily send limit exceeded | Upgrade tier or wait until tomorrow |
535 5.7.8 | Authentication failed | Verify username/password, check for rotation |
554 5.7.1 | Relay access denied | Ensure you're using STARTTLS/TLS auth |
421 4.7.0 | Too many connections | Rate limit SMTP connections |
Next Steps
- Sending & Receiving - REST API email flow
- Deliverability - Ensure emails reach inboxes
- API Reference: Get SMTP Credentials - Full API docs