daimon.email
Fundamentals

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

TierSMTP AccessCredentials
Free❌ DisabledN/A
Starter✅ EnabledPer-account
Pro✅ EnabledPer-account
Enterprise✅ EnabledPer-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

SettingValueNotes
Hostsmtp.daimon.emailShared pool (Starter/Pro), dedicated IP (Enterprise)
Port587 (STARTTLS) or 465 (TLS)Port 25 blocked to prevent spam
SecuritySTARTTLS or TLSTLS/SSL encryption required
Auth MethodPLAINUsername/password authentication
UsernameYour API key (e.g., dm_live_...)Account-level credential
PasswordSMTP password from /v1/account/smtpRotates on demand
From AddressAny 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

TierIMAP AccessCredentials
Free❌ DisabledN/A
Starter✅ PlannedPer-inbox
Pro✅ PlannedPer-inbox
Enterprise✅ PlannedPer-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-THRID extension

When to Use SMTP/IMAP vs REST API

Use CaseRecommended ApproachWhy
AI agent sending emailREST APISimpler, includes threading, webhooks, rate limit handling
AI agent receiving emailREST API + WebhooksReal-time delivery, parsed fields (reply_body, cta_links)
Integrating legacy email toolsSMTP/IMAPCompatibility with existing libraries
Email client (Thunderbird, Outlook)IMAP (when available)Standard protocol support
Sending bulk campaignsREST APIBetter rate limiting, analytics, bounce handling
Migrating existing SMTP codeSMTPDrop-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 this

2. 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 30s

4. 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 CodeMeaningSolution
550 5.7.1Unauthorized sender addressUse an inbox you own in From: header
550 5.7.26Daily send limit exceededUpgrade tier or wait until tomorrow
535 5.7.8Authentication failedVerify username/password, check for rotation
554 5.7.1Relay access deniedEnsure you're using STARTTLS/TLS auth
421 4.7.0Too many connectionsRate limit SMTP connections

Next Steps