Base URL
https://app.dmu.email/api/v1
Authentication
Bearer dmk_… API key
Rate limit
120 requests a minute per key

Send a draft

POST/drafts/{id}/send

Queues a draft for sending. It leaves after the 30-second undo window, or at sendAt if you set one. Sending the same draft twice is safe: the second call returns the same message with alreadySent set to true.

Needs the permissiondrafts:send

Path parameters

idstringrequired
The draft to send.

Body

sendAtstringoptional
When to send it, as an ISO 8601 time. Leave it out to send as soon as the undo window closes.

Returns

messageIdstring
The message that will be sent. It’s the draft’s own id.
threadIdstring
The conversation it belongs to.
statusstring
queued, or scheduled with sendAt. Poll GET /messages/{id} to see sending, sent or failed.
scheduledAtstring or null
When it will go, if you set sendAt.
undoSecondsnumber
How long it can still be cancelled: 30. A scheduled send says 0, and can be cancelled until its time. Delete the draft to cancel.
alreadySentboolean
Only on a repeat call: true, and nothing was sent again.

Errors

400no_recipient
The draft has no one in to.
400bad_send_at
sendAt isn’t an ISO 8601 time, or send_at_in_past: it has passed.
400send_failed
It couldn’t be queued. The message says why.
401invalid_key
The key is wrong, expired or revoked. With no Authorization header at all, the code is missing_credentials.
403missing_scope
The key doesn’t have drafts:send. The X-Required-Scope header names what’s missing.
404not_found
There is no such draft, or the key’s owner can’t see it.
409draft_locked
Somebody has the draft open in DMU Mail right now.
429rate_limited
More than 120 requests, or more than 30 sends, a minute from this key. Wait for Retry-After seconds.
curl https://app.dmu.email/api/v1/drafts/8c1e2f4a/send \
  -X POST \
  -H "Authorization: Bearer dmk_7f3a9c2e1b4d_Xq8v…" \
  -H "Content-Type: application/json" \
  -d '{ "sendAt": "2026-09-28T09:00:00+03:00" }'

Response

200 OK

{
  "data": {
    "messageId": "8c1e2f4a",
    "threadId": "f3d86b25",
    "status": "scheduled",
    "scheduledAt": "2026-09-28T06:00:00.000Z",
    "undoSeconds": 0
  }
}

Every response wraps its result in data. A page of threads adds nextCursor, which is null on the last page.