AgentPost
Core Concepts

Drafts

Compose messages before sending with full revision support

A draft is an unsent message. Drafts let your agent compose email incrementally -- setting recipients, writing content, attaching files -- before committing to send. This is useful for workflows that need human review or multi-step composition.

Key properties

PropertyDescription
idUnique identifier (prefix drf_)
inbox_idThe inbox this draft belongs to
thread_idOptional thread to reply in
in_reply_toOptional Message-ID being replied to
subjectEmail subject line
to_addressesArray of recipient emails
cc_addressesCarbon copy recipients
bcc_addressesBlind carbon copy recipients
text_bodyPlain text body
html_bodyHTML body
attachments_metaMetadata for attached files

Draft lifecycle

Create --> Edit (multiple times) --> Send or Delete
  1. Create -- Create a draft with initial content
  2. Edit -- Update any fields (recipients, subject, body, attachments)
  3. Send -- Convert the draft into a sent message and deliver it
  4. Delete -- Discard the draft without sending

When a draft is sent, it is deleted and a new message is created in its place. The draft ID is no longer valid after sending.

Creating a draft

const draft = await client.drafts.create('inb_abc123', {
  to: [{ email: 'legal@acmeco.com', name: 'Legal Team' }],
  subject: 'Contract review request: Vendor Agreement #891',
  text_body: 'Please review the attached vendor agreement. Key terms to verify:\n\n1. Payment terms (Net 30 vs Net 60)\n2. Liability cap\n3. Termination clause\n\nI will hold off on signing until I hear back.',
});

console.log(`Draft created: ${draft.id}`);
draft = client.drafts.create(
    inbox_id="inb_abc123",
    to=[{"email": "legal@acmeco.com", "name": "Legal Team"}],
    subject="Contract review request: Vendor Agreement #891",
    text_body="Please review the attached vendor agreement.",
)

print(f"Draft created: {draft.id}")
curl -X POST https://api.agent-post.dev/api/v1/inboxes/inb_abc123/drafts \
  -H "Authorization: Bearer $AGENTPOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": [{"email": "legal@acmeco.com", "name": "Legal Team"}],
    "subject": "Contract review request: Vendor Agreement #891",
    "text_body": "Please review the attached vendor agreement."
  }'

Updating a draft

const updated = await client.drafts.update('drf_xyz789', {
  cc: [{ email: 'cfo@acmeco.com', name: 'CFO' }],
  text_body: 'Updated: Please review the attached vendor agreement. Adding CFO for visibility on the payment terms discussion.',
});
updated = client.drafts.update(
    draft_id="drf_xyz789",
    cc=[{"email": "cfo@acmeco.com", "name": "CFO"}],
    text_body="Updated: Please review the attached vendor agreement.",
)
curl -X PATCH https://api.agent-post.dev/api/v1/drafts/drf_xyz789 \
  -H "Authorization: Bearer $AGENTPOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "cc": [{"email": "cfo@acmeco.com", "name": "CFO"}],
    "text_body": "Updated: Please review the attached vendor agreement."
  }'

Sending a draft

const message = await client.drafts.send('drf_xyz789');

console.log(`Draft sent as message: ${message.id}`);
// The draft no longer exists after sending
message = client.drafts.send("drf_xyz789")

print(f"Draft sent as message: {message.id}")
curl -X POST https://api.agent-post.dev/api/v1/drafts/drf_xyz789/send \
  -H "Authorization: Bearer $AGENTPOST_API_KEY"

Thread-linked drafts

Create a draft that replies to an existing conversation by providing thread_id and in_reply_to:

const replyDraft = await client.drafts.create('inb_abc123', {
  thread_id: 'thr_ghi789',
  in_reply_to: 'msg_def456',
  to: [{ email: 'alice@example.com' }],
  text_body: 'Working on this now. Will have an update by end of day.',
});
reply_draft = client.drafts.create(
    inbox_id="inb_abc123",
    thread_id="thr_ghi789",
    in_reply_to="msg_def456",
    to=[{"email": "alice@example.com"}],
    text_body="Working on this now. Will have an update by end of day.",
)
curl -X POST https://api.agent-post.dev/api/v1/inboxes/inb_abc123/drafts \
  -H "Authorization: Bearer $AGENTPOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "thread_id": "thr_ghi789",
    "in_reply_to": "msg_def456",
    "to": [{"email": "alice@example.com"}],
    "text_body": "Working on this now. Will have an update by end of day."
  }'

Validation at send time

The thread_id and in_reply_to fields are not validated when creating the draft. Validation happens when you send the draft -- if the thread or message does not exist at that point, the send will fail.

Attachments in drafts

Attachments are stored as metadata (S3 keys) in the draft. When the draft is sent, the attachment S3 keys are transferred to the resulting message.

See Attachments for details on uploading files.

Relationships

  • A draft belongs to one inbox (inbox_id)
  • A draft can optionally be linked to a thread (thread_id)
  • When sent, the draft is replaced by a message
  • Drafts can reference attachments via attachments_meta
  • Drafts are scoped to an environment via their inbox

Tips

  • Drafts are ideal for workflows requiring human-in-the-loop review before sending
  • The delete-first pattern is used internally: when sending, the draft is deleted before the email is dispatched to prevent duplicate sends on retry
  • Listing drafts returns all unsent drafts for an inbox -- useful for showing pending outbox items
  • Draft IDs become invalid after sending. Use the returned message object to get the new message ID.

On this page