Черновики

Подготовка и отложенная отправка сообщений для агентов.

Что такое черновик?

Draft — это ещё не отправленное Message. Ресурс, в котором агент готовит письмо: получатели, тема, тело и Attachments — без немедленной отправки.

Надёжность агентов сегодня на первом плане: с Drafts письма могут быть готовы к отправке, а уйти в мир только с вашего разрешения.

Drafts важны для продвинутых сценариев:

  • Human-in-the-loop: агент создаёт Draft для чувствительного или важного письма; человек проверяет и одобряет перед отправкой.
  • Отправка по расписанию: агент создаёт Draft, отдельный процесс отправляет его в нужное время (например в рабочие часы получателя).
  • Сложная сборка: если письмо собирается из нескольких шагов (данные из разных источников, генерация текста), черновик сохраняет промежуточное состояние.

Жизненный цикл Draft

От создания до отправки.

1. Создать Draft

Нужен Inbox, от имени которого потом пойдёт отправка.

1# Нужен inbox_id для создания черновика
2
3new_draft=client.inboxes.drafts.create(
4 inbox_id="outbound@domain.com",
5 to=["review-team@example.com"],
6 subject="[NEEDS REVIEW] Agent's proposed response"
7)
8
9print(f"Draft created successfully with ID: {new_draft.draft_id}")

2. Получить Draft

После создания — по ID.

1# Получить черновик
2draft = client.inboxes.drafts.get(inbox_id = "my_inbox@domain.com", draft_id = "draft_id_123")

3. Отправить Draft

Финальный шаг: черновик превращается в отправленное Message и удаляется.

1# Отправка удаляет черновик
2
3sent_message = client.inboxes.drafts.send(inbox_id = 'my_inbox@domain.com', draft_id = 'draft_id_123')
4
5print(f"Draft sent! New message ID: {sent_message.message_id}")

Дальше к письму обращайтесь уже по message_id — это уже сообщение.

Отправка по расписанию

Черновик можно запланировать на будущее, передав поле send_at при создании или обновлении. Agent Inbox отправит его в указанное время — без cron и опроса.

Запланировать Draft

Передайте дату-время в формате ISO 8601 в send_at. Черновик автоматически получит метку scheduled, а send_status станет scheduled.

1from datetime import datetime, timedelta
2
3# Завтра в 9:00 UTC
4send_time = (datetime.utcnow() + timedelta(days=1)).replace(
5 hour=9, minute=0, second=0
6)
7
8scheduled_draft = client.inboxes.drafts.create(
9 inbox_id="outreach@domain.com",
10 to=["prospect@example.com"],
11 subject="Following up on our conversation",
12 text="Hi, just wanted to follow up on our chat yesterday...",
13 send_at=send_time.isoformat() + "Z"
14)
15
16print(f"Draft scheduled for {scheduled_draft.send_at}")
17# send_status будет "scheduled"

Отмена или перенос

Чтобы отменить запланированную отправку — удалите Draft. Чтобы перенести — обновите send_at.

1# Перенос на другое время
2new_time = (datetime.utcnow() + timedelta(days=3)).replace(hour=14, minute=0, second=0)
3client.inboxes.drafts.update(
4 inbox_id="outreach@domain.com",
5 draft_id=scheduled_draft.draft_id,
6 send_at=new_time.isoformat() + "Z"
7)
8
9# Или отмена полным удалением черновика
10client.inboxes.drafts.delete(
11 inbox_id="outreach@domain.com",
12 draft_id=scheduled_draft.draft_id
13)

Список запланированных Draft

Если при создании указан send_at, ставится метка scheduled. Фильтр по параметру labels.

1# Все запланированные черновики в inbox
2scheduled = client.inboxes.drafts.list(
3 inbox_id="outreach@domain.com",
4 labels=["scheduled"]
5)
6
7for draft in scheduled.drafts:
8 print(f"{draft.subject} — scheduled for {draft.send_at} ({draft.send_status})")
Значения send_status
  • scheduled — в очереди, отправка в момент send_at.
  • sending — идёт отправка.
  • failed — ошибка отправки. Повтор: обновите send_at на новое время.

Условные фоллоу-апы

Частый паттерн: «фоллоу-ап через 3 дня, если не ответили». Создайте запланированный черновик фоллоу-апа и отмените его через Webhook, если пришёл ответ.

1. Первое письмо и план фоллоу-апа:

1from datetime import datetime, timedelta
2
3inbox_id = "outreach@domain.com"
4
5# Первое письмо
6initial = client.inboxes.messages.send(
7 inbox_id=inbox_id,
8 to=["prospect@example.com"],
9 subject="Quick question about your workflow",
10 text="Hi, I noticed your team is scaling quickly..."
11)
12
13# Фоллоу-ап через 3 дня
14follow_up_time = (datetime.utcnow() + timedelta(days=3)).replace(hour=9, minute=0, second=0)
15
16follow_up = client.inboxes.drafts.create(
17 inbox_id=inbox_id,
18 to=["prospect@example.com"],
19 subject="Re: Quick question about your workflow",
20 text="Hi again — just bumping this in case it got buried...",
21 in_reply_to=initial.message_id,
22 send_at=follow_up_time.isoformat() + "Z"
23)
24
25# Метка на треде для обработчика вебхука
26client.inboxes.threads.update(
27 inbox_id=inbox_id,
28 thread_id=initial.thread_id,
29 add_labels=[f"follow-up:{follow_up.draft_id}"]
30)

2. Отмена при ответе (вебхук):

При входящем ответе ищите на треде метку follow-up:<draft_id> и удалите черновик.

1# В обработчике вебхука для "message.received":
2thread = client.inboxes.threads.get(inbox_id=inbox_id, thread_id=thread_id)
3
4for label in thread.labels:
5 if label.startswith("follow-up:"):
6 draft_id = label.split("follow-up:")[1]
7 try:
8 client.inboxes.drafts.delete(inbox_id=inbox_id, draft_id=draft_id)
9 except Exception:
10 pass # Черновик мог уже уйти
11 client.inboxes.threads.update(
12 inbox_id=inbox_id, thread_id=thread_id,
13 remove_labels=[label]
14 )
15 break

Если лид ответил — фоллоу-ап отменяется. Если нет — уходит по расписанию.

Организация: все Draft по организации

Как и для Threads, можно получить все Draft по всей Organization — удобно для единой панели, где супервайзер видит, одобряет или удаляет черновики любых агентов.

1# Все черновики организации
2all_drafts = client.drafts.list()
3
4print(f"Found {all_drafts.count} drafts pending review.")

Скопировать в Cursor / Claude

1"""
2Agent Inbox Drafts — copy into Cursor/Claude.
3
4Setup: pip install agentinbox python-dotenv. Set AGENTINBOX_API_KEY in .env.
5
6API reference:
7- inboxes.drafts.create(inbox_id, to, subject?, text?, html?, cc?, bcc?, reply_to?, attachments?, send_at?)
8- inboxes.drafts.get(inbox_id, draft_id)
9- inboxes.drafts.update(inbox_id, draft_id, to?, subject?, text?, html?, send_at?, ...)
10- inboxes.drafts.send(inbox_id, draft_id) — converts to Message, deletes draft
11- inboxes.drafts.delete(inbox_id, draft_id)
12- inboxes.drafts.list(inbox_id, limit?, page_token?, labels?)
13- drafts.list(limit?, page_token?) — org-wide
14
15Scheduled sending: pass send_at (ISO 8601 datetime) to create() or update().
16Draft is auto-labeled 'scheduled' and sent at the specified time.
17send_status: 'scheduled' | 'sending' | 'failed'.
18Cancel by deleting the draft. Reschedule by updating send_at.
19
20Errors: SDK raises on 4xx/5xx. Rate limit: 429 with Retry-After.
21"""
22import os
23from datetime import datetime, timedelta
24from dotenv import load_dotenv
25from agentinbox import Agentinbox
26
27load_dotenv()
28client = Agentinbox(api_key=os.getenv("AGENTINBOX_API_KEY"))
29
30inbox_id = "agent@agentinbox.space"
31
32# Create and send immediately
33draft = client.inboxes.drafts.create(inbox_id, to=["review@example.com"], subject="[REVIEW] Proposed reply")
34sent = client.inboxes.drafts.send(inbox_id, draft.draft_id)
35print(sent.message_id)
36
37# Schedule for later
38send_time = (datetime.utcnow() + timedelta(days=1)).replace(hour=9, minute=0, second=0)
39scheduled = client.inboxes.drafts.create(
40 inbox_id, to=["prospect@example.com"], subject="Follow up",
41 text="Just following up...", send_at=send_time.isoformat() + "Z"
42)
43print(f"Scheduled for {scheduled.send_at}, status: {scheduled.send_status}")
44
45all_drafts = client.drafts.list()