daimon.email
Api referenceMessages

Send Email

Send an email from your inbox (requires paid tier)

Warning

Paid tier required - Free tier inboxes cannot send emails. When a free tier agent calls this endpoint, it receives a 402 Payment Required response with an upgrade flow that the agent can autonomously handle.

Authentication

Requires the inbox's API key in the Authorization header.

Path Parameters

idstringpathrequired

Inbox ID (e.g., inb_abc123)

Request Body

tostring or arraybodyrequired

Recipient email address(es). Can be a single string or array of strings.

ccstring or arraybody

CC recipients (optional)

bccstring or arraybody

BCC recipients (optional)

subjectstringbodyrequired

Email subject line

bodystringbodyrequired

Plain text body

body_htmlstringbody

HTML body (optional)

in_reply_tostringbody

Message-ID this email is replying to (sets In-Reply-To header)

referencesarraybody

Array of Message-IDs for threading (sets References header)

thread_idstringbody

Thread UUID to attach this message to

client_idstringbody

Idempotency key - prevents duplicate sends on retry

send_atstringbody

ISO 8601 datetime - schedule for future delivery (optional)

draft_idstringbody

Draft UUID to send (optional)

Request

curl -X POST "https://api.daimon.email/v1/inboxes/inb_abc123/send" \
  -H "Authorization: Bearer dm_live_7d8a9b0c1d2e3f4g5h6i7j8k9l0m1n2o" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "user@example.com",
    "subject": "Hello from my agent",
    "body": "This is my first email sent via daimon.email!",
    "client_id": "send-001"
  }'
const client = new DaimonClient({ apiKey: 'dm_live_...' });

try {
  const sent = await client.inboxes.send('inb_abc123', {
    to: 'user@example.com',
    subject: 'Hello from my agent',
    body: 'This is my first email sent via daimon.email!',
    clientId: 'send-001'
  });

  console.log(`Sent! Message ID: ${sent.message_id}`);
  console.log(`Status: ${sent.status}`);
} catch (error) {
  if (error.code === 'SEND_REQUIRES_PAID') {
    // Agent autonomously handles upgrade flow
    console.log('Agent script:', error.upgradeContext.agentScript);
    // Outputs: "Tell your operator: I need sending access. Here's a direct upgrade link: https://..."

    // Generate magic upgrade link
    const upgradeLink = await client.account.createUpgradeLink();
    console.log('Upgrade URL:', upgradeLink.url);
  }
}
client = DaimonClient(api_key='dm_live_...')

try:
    sent = client.inboxes.send('inb_abc123', {
        'to': 'user@example.com',
        'subject': 'Hello from my agent',
        'body': 'This is my first email sent via daimon.email!',
        'client_id': 'send-001'
    })

    print(f"Sent! Message ID: {sent.message_id}")
    print(f"Status: {sent.status}")
except DaimonError as e:
    if e.code == 'SEND_REQUIRES_PAID':
        # Agent autonomously handles upgrade flow
        print('Agent script:', e.upgrade_context['agent_script'])
        # Outputs: "Tell your operator: I need sending access. Here's a direct upgrade link: https://..."

        # Generate magic upgrade link
        upgrade_link = client.account.create_upgrade_link()
        print('Upgrade URL:', upgrade_link.url)

Response

Response

{
  "result": {
    "id": "msg_sent123",
    "status": "sent",
    "message_id": "<abc123@daimon.email>",
    "sent_at": "2024-03-11T14:23:45Z",
    "note": null
  },
  "next_steps": [
    "Message delivered successfully",
    "Check /v1/inboxes/{id}/messages for replies",
    "Monitor webhooks for message.reply events"
  ]
}
{
  "result": {
    "id": "msg_sched456",
    "status": "scheduled",
    "message_id": "<def456@daimon.email>",
    "sent_at": null,
    "scheduled_at": "2024-03-12T09:00:00Z",
    "note": "Scheduled for delivery at 2024-03-12T09:00:00Z"
  },
  "next_steps": [
    "Message scheduled for future delivery",
    "Call DELETE /v1/inboxes/{id}/scheduled/{id} to cancel",
    "Message will appear in /v1/inboxes/{id}/messages after delivery"
  ]
}
{
  "error": "SEND_REQUIRES_PAID",
  "message": "Sending emails requires a paid tier subscription",
  "upgrade_context": {
    "operator_action_url": "https://daimon.email/upgrade?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "operator_action_label": "Add a payment method to enable sending",
    "agent_script": "Tell your operator: I need sending access. Here's a direct upgrade link: https://daimon.email/upgrade?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  },
  "next_steps": [
    "Present the operator_action_url to your human operator",
    "Or call POST /v1/upgrade-link to generate a new magic upgrade link",
    "After upgrade, retry this request with the same client_id for idempotency"
  ]
}
{
  "error": "SEND_LIMIT_EXCEEDED",
  "message": "Monthly send limit reached (100/100). Upgrade to increase limit.",
  "upgrade_context": {
    "operator_action_url": "https://daimon.email/upgrade?token=...",
    "operator_action_label": "Upgrade to Pro for 10,000 sends/month",
    "agent_script": "Tell your operator: I've hit the monthly send limit. Here's an upgrade link: https://daimon.email/upgrade?token=..."
  },
  "next_steps": [
    "Present the upgrade link to your operator",
    "Or wait until the next billing cycle (resets on the 1st of each month)"
  ]
}

Response Fields

result.idstring

Sent message ID

result.statusstring

Delivery status: queued, sent, or scheduled

result.message_idstring

RFC 5322 Message-ID header (e.g., <abc123@daimon.email>)

result.sent_atstring

ISO 8601 timestamp of when the message was sent (null if scheduled)

result.scheduled_atstring

ISO 8601 timestamp of when the message will be sent (null if sent immediately)

result.notestring

Additional delivery information

next_stepsarray

Agent guidance for next actions

Error Response Fields

errorstring

Error code: SEND_REQUIRES_PAID, SEND_LIMIT_EXCEEDED, SMTP_REQUIRES_PAID

messagestring

Human-readable error description

upgrade_context.operator_action_urlstring

Magic upgrade link - agent presents this to the human operator

upgrade_context.operator_action_labelstring

Button text / CTA for the operator

upgrade_context.agent_scriptstring

Ready-to-use message the agent can send to the operator

Use Cases

Autonomous upgrade handling (free tier agent)
// Agent checks capabilities before sending
const capabilities = await client.account.getCapabilities();

const canSend = capabilities.can.find(c => c.action === 'send_messages');

if (!canSend) {
  // Generate magic upgrade link
  const upgradeLink = await client.account.createUpgradeLink();

  // Agent autonomously messages operator
  await notifyOperator({
    message: "I need sending access to complete this task.",
    action_url: upgradeLink.url,
    action_label: "Enable sending (takes 60 seconds)"
  });

  // Wait for upgrade...
  await pollForUpgrade();

  // Retry send
  const sent = await client.inboxes.send('inb_abc123', {
    to: 'user@example.com',
    subject: 'Hello',
    body: 'Now I can send!',
    clientId: 'send-001' // Same client_id ensures idempotency
  });
}
Schedule future delivery
const sent = await client.inboxes.send('inb_abc123', {
  to: 'user@example.com',
  subject: 'Scheduled follow-up',
  body: 'This will be sent tomorrow at 9am',
  sendAt: '2024-03-12T09:00:00Z',
  clientId: 'followup-001'
});

console.log(`Scheduled for: ${sent.scheduled_at}`);
Send with idempotency
// Agent can safely retry failed requests
const clientId = `send-${Date.now()}`;

try {
  const sent = await client.inboxes.send('inb_abc123', {
    to: 'user@example.com',
    subject: 'Important',
    body: 'This will only be sent once',
    clientId: clientId
  });
} catch (error) {
  if (error.code === 'NETWORK_ERROR') {
    // Retry with same client_id - will not duplicate
    const sent = await client.inboxes.send('inb_abc123', {
      to: 'user@example.com',
      subject: 'Important',
      body: 'This will only be sent once',
      clientId: clientId // Same ID = idempotent retry
    });
  }
}
Send HTML email
const sent = await client.inboxes.send('inb_abc123', {
  to: 'user@example.com',
  subject: 'Rich HTML email',
  body: 'This is the plain text version',
  bodyHtml: '<h1>Hello!</h1><p>This is the <strong>HTML</strong> version</p>',
  clientId: 'html-001'
});