Review an agent email draft before sending the exact message
Bind approval to recipients, content and attachments, then preserve one send identity through retries.
Create, update and retire drafts while preserving source messages and separating drafting from sending.
A draft gives an agent somewhere to put proposed email content without sending it. That boundary is especially useful for autonomous registration, whose initial key can create drafts while outgoing email remains disabled. Store the returned draft_id with the work item and source message IDs so the operator can locate the proposal after a worker restart. A draft existing in the inbox is not evidence of human approval. Keep your application’s review status explicit rather than treating an empty send_at field or a particular subject prefix as consent.
Create through POST /v0/emails/inboxes/:inbox_id/emails/drafts and supply a stable client_id when you need creation deduplication. A normal draft can include recipients, subject, text and attachments. Set in_reply_to for a reply draft or forward_of for a forward draft; those fields are mutually exclusive. Reply drafts derive conversation details from their source, while reply_all cannot be combined with explicit to, cc or bcc fields. Choose the intended operation at creation instead of relying on the model to repair contradictory fields after a validation failure.
{"to":["reviewer@example.com"],"subject":"Proposed response","text":"Please review this draft.","client_id":"case-104-proposal-1"}PATCH on the draft resource supports field changes, nullable clears, attachment additions/removals, label changes and send_at updates. Build patches from deliberate edits rather than serializing an entire partially populated form, which can accidentally clear fields. Keep a local content revision or digest for review: if a model rewrites recipients or attaches a new file after approval, the old approval no longer describes the current proposal. Read the current draft again before showing a final review when more than one worker or human can edit it. Scheduling through a non-null send_at requires draft_send authority; a less-privileged worker must cancel an existing schedule before editing that scheduled draft.
POST /v0/emails/inboxes/:inbox_id/emails/drafts/:draft_id/send returns the sent email and deletes the draft on successful delivery submission. Forwarded content and attachments merge at send time, so review needs to account for the source resource as well as the editable body. A missing draft after an uncertain send is not enough evidence to claim delivery; preserve the send operation identity and inspect the resulting message or recorded outcome. A draft that still exists may also have a failed or scheduled state requiring explicit inspection.
Delete abandoned drafts when the underlying request is withdrawn or superseded, after recording the local reason if your workflow needs an audit trail. Avoid silently overwriting an older human-edited draft with a fresh model response. Scheduled drafts add another lifecycle boundary because the cron can attempt them later without an interactive worker waiting. Your next step is a state diagram in your own application covering proposed, under-review, approved, scheduled, sent, failed and abandoned. Tie every transition to a real returned resource state or authorized human decision rather than an optimistic model summary.
A repeated client_id can recover an existing draft rather than create a revised proposal. If the task genuinely changes, read and update the saved draft deliberately or create a new proposal identity after retiring the old one. Do not assume replaying draft creation with changed text is the same as editing that resource; keep creation recovery and content revision separate.
Reviewed against checked-in Lupin API handlers and documentation. Example requests were not executed against live providers.
Prepared with AI assistance by Lupin editorial. How we research and maintain these guides.