daimon.email
Api referenceDrafts

Send Draft

Send a draft email immediately or at scheduled time

Overview

Send an email draft. If the draft has a send_at timestamp in the future, it will be scheduled for delivery at that time. Otherwise, it will be sent immediately.

Warning

Sending emails requires a paid tier (Developer or higher). Free tier accounts will receive a 402 SEND_REQUIRES_PAID error with upgrade context.

Authentication

Authorizationstringpathrequired

Inbox API Key

Path Parameters

idstringpathrequired

The inbox ID (e.g., inb_abc123)

draftIdstringpathrequired

The draft ID (e.g., dft_abc123)

Body Parameters

No request body required.

Request

curl -X POST https://api.daimon.email/v1/inboxes/inb_abc123/drafts/dft_abc123/send \
  -H "Authorization: Bearer dm_free_7d8a9b0c1d2e3f4g5h6i7j8k9l0m1n2o"
import { DaimonClient } from 'daimon-email';

const client = new DaimonClient({
  apiKey: 'dm_free_7d8a9b0c1d2e3f4g5h6i7j8k9l0m1n2o'
});

try {
  const result = await client.inboxes.drafts.send('inb_abc123', 'dft_abc123');

  console.log(`Status: ${result.status}`);
  console.log(`Message ID: ${result.message_id}`);

  if (result.status === 'scheduled') {
    console.log(`Will be sent at: ${result.scheduled_at}`);
  } else {
    console.log(`Sent at: ${result.sent_at}`);
  }
} catch (error) {
  if (error.code === 'SEND_REQUIRES_PAID') {
    // Handle upgrade flow
    console.log('Upgrade required:', error.upgradeContext.agent_script);

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

client = DaimonClient(
    api_key='dm_free_7d8a9b0c1d2e3f4g5h6i7j8k9l0m1n2o'
)

try:
    result = client.inboxes.drafts.send('inb_abc123', 'dft_abc123')

    print(f"Status: {result['status']}")
    print(f"Message ID: {result['message_id']}")

    if result['status'] == 'scheduled':
        print(f"Will be sent at: {result['scheduled_at']}")
    else:
        print(f"Sent at: {result['sent_at']}")

except DaimonError as e:
    if e.code == 'SEND_REQUIRES_PAID':
        # Handle upgrade flow
        print(f"Upgrade required: {e.upgrade_context['agent_script']}")

        # Generate magic upgrade link
        upgrade_link = client.account.create_upgrade_link()
        print(f"Upgrade URL: {upgrade_link['url']}")

Response

{
  "result": {
    "id": "msg_abc123",
    "status": "queued",
    "message_id": "<abc123@daimon.email>",
    "sent_at": "2024-03-11T16:45:00Z",
    "scheduled_at": null,
    "note": "Email queued for delivery"
  },
  "next_steps": [
    "Use GET /v1/inboxes/{id}/messages/{messageId} to check delivery status",
    "Register a webhook to receive 'message.sent' events",
    "Monitor delivery via GET /v1/inboxes/{id}/messages"
  ]
}
{
  "result": {
    "id": "msg_def456",
    "status": "scheduled",
    "message_id": "<def456@daimon.email>",
    "sent_at": null,
    "scheduled_at": "2024-03-12T09:00:00Z",
    "note": "Email scheduled for delivery at 2024-03-12T09:00:00Z"
  },
  "next_steps": [
    "Use PATCH /v1/inboxes/{id}/drafts/{draftId} to reschedule before send time",
    "Use DELETE /v1/inboxes/{id}/drafts/{draftId} to cancel scheduled send",
    "Register a webhook to receive 'message.sent' events when delivered"
  ]
}
{
  "error": "SEND_REQUIRES_PAID",
  "message": "Sending emails requires a paid tier",
  "upgrade_context": {
    "operator_action_url": "https://daimon.email/upgrade?token=eyJhbGc...",
    "operator_action_label": "Add a payment method to enable sending",
    "agent_script": "Tell your operator: I need sending access to complete the customer notification. Here's a direct upgrade link: https://daimon.email/upgrade?token=eyJhbGc..."
  }
}

Response Fields

Success Response

result.idstring

Message ID (converted from draft after sending)

result.statusstring

Delivery status: queued (immediate send) or scheduled (future send)

result.message_idstring

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

result.sent_atstring

ISO 8601 timestamp when email was sent (null if scheduled)

result.scheduled_atstring

ISO 8601 timestamp when email will be sent (null if sent immediately)

result.notestring

Human-readable status message

next_stepsarray

Suggested actions the agent can take next

Error Response (402 Payment Required)

errorstring

Error code: SEND_REQUIRES_PAID

messagestring

Human-readable error message

upgrade_contextobject

Information to help the agent request an upgrade

Upgrade context object
operator_action_urlstring

Magic link for operator to upgrade account (no login required)

operator_action_labelstring

Button label for the upgrade action

agent_scriptstring

Complete script the agent can use to communicate the upgrade need to the operator

Handling Upgrades

When your agent hits the send limit, it should handle the upgrade flow gracefully:

class EmailAgent {
  async sendDraft(inboxId: string, draftId: string) {
    try {
      const result = await this.client.inboxes.drafts.send(inboxId, draftId);
      return result;
    } catch (error) {
      if (error.code === 'SEND_REQUIRES_PAID') {
        // Notify operator with upgrade script
        await this.notifyOperator({
          message: error.upgradeContext.agent_script,
          action_url: error.upgradeContext.operator_action_url,
          action_label: error.upgradeContext.operator_action_label
        });

        // Queue the draft for retry after upgrade
        await this.queueForRetry(inboxId, draftId);

        return {
          status: 'pending_upgrade',
          draft_id: draftId
        };
      }
      throw error;
    }
  }
}

See the Magic Upgrade Flow guide for complete implementation patterns.

Delivery Status

After sending, you can track delivery status:

// Check delivery status
const message = await client.inboxes.messages.get('inb_abc123', 'msg_abc123');

console.log('Delivery status:', message.delivery_status);
// Possible values: queued, sent, delivered, bounced, failed

Info

Once a draft is sent, it is converted to a message and can no longer be edited. The draft is automatically deleted after successful send.