Integrate the mail API and gateway handoff
The mail API is tenant-bound and uses standard Workspace permissions. Clients receive mail content only through ACL-checked Storage URLs.
This reference is for developers of mail work surfaces and private gateway adapters. It defines the authoritative HTTP and SMTP contracts. Follow Provide mail through an SMTP gateway for operational setup.
Check the contract with nucli
Use nucli so authentication, tenant selection, and permissions remain in the server contract. The built-in skill documents the safe sequence for read-only checks and explicitly approved mutations:
nucli skills show mail
nucli --tenant <tenant> whoami --scopes
nucli --tenant <tenant> api GET /api/v1/mail/mailboxes --summary
nucli --tenant <tenant> api GET \
'/api/v1/mail/threads?class=screener&limit=25' --summaryPass request bodies with --input <file> or --input -. Do not expose subjects, bodies, addresses, notes, Storage URLs, or attachments in agent logs. Use --summary when only HTTP and response metadata are required.
Connect a work surface
GET /api/v1/mail/mailboxesreturns visible personal and shared mailboxes.GET /api/v1/mail/threadsacceptsclass,mine,limit, andoffset.GET /api/v1/mail/threads/{id}returns work state and Storage references.GET /api/v1/mail/search?q=…uses the permission-checked blind index.POST /api/v1/mail/sendstores RFC822 and its projection encrypted and queues the same Storage reference once per envelope recipient. Pass readable attachments asattachmentObjectIds./api/v1/mail/draftsmanages encrypted, author-only drafts./api/v1/mail/threads/{id}/notesmanages encrypted internal notes.POST /api/v1/mail/threads/{id}/assistreturns only an assistive summary and reply suggestion through theMAIL_ASSISTpolicy task.
Seen state, move, take/assignment, screening, follow-up, and explicit Inbox projection commands live under /api/v1/mail/threads/{id}/….
Use GET /api/v1/mail/imported-containers to list imported source folders. GET /api/v1/mail/imported-containers/{containerID}/thread-pages returns stable ACL-filtered pages for one folder. These folders are a read-only source view and remain separate from normal work classes.
Compose and send mail safely
The interactive composer uses this sequence:
GET /api/v1/mail/compose/readinesschecks local prerequisites.GET /api/v1/mail/compose/templateslists effective templates from themailbox/composenamespace. It supportslocale,q,count,pageoroffset, and the fixedkey ASCorder.POST /api/v1/mail/compose/previewrenders the complete message.POST /api/v1/mail/compose/sendreceives the same request plus the returnedpreviewDigest.
The digest is bound to its tenant, identity, and input and expires after ten minutes. The server renders again before sending. Repeating an identical confirmed request returns the same result without creating another message. Changing any field requires a new preview.
Attachments require read access, the same tenant, an approved business Storage context, and an allowed scan state when scanning is active. Never copy subject, body, or attachments into logs, audit metadata, Conversation fields, or queue payloads. Use the returned Storage references.
Interpret SMTP responses
The private listener validates recipients during RCPT TO:
250: the recipient is active and routable.550: the domain, address, mailbox, or bounce recipient is unavailable.451: a temporary lookup or Storage failure; the gateway must retry.250 storedafterDATA: original, projection, ACL, blind index, and intake ledger are durably published.
The client must connect with TLS 1.3 and an allowlisted mTLS certificate. Do not expose this contract as a public SMTP listener.
Connect a provider-neutral mail transfer adapter
The adapter needs mail:import. This permission does not grant read, search, download, or export access to mail content. Call the endpoints in this order:
POST /api/v1/mail/transfer/sessionsPOST /api/v1/mail/transfer/sessions/{sessionID}/containersPOST /api/v1/mail/transfer/sessions/{sessionID}/batchesPUT /api/v1/mail/transfer/batches/{batchID}/itemsPOST /api/v1/mail/transfer/batches/{batchID}/reconcileGET /api/v1/mail/transfer/batches/{batchID}until the status isreadyPOST /api/v1/mail/transfer/batches/{batchID}/publishGET /api/v1/mail/transfer/batches?limit=50for the tenant-scoped operational view without source identifiers or mail content
The item request uses multipart/form-data. The first part is named metadata and contains JSON. For upsert, the second part must be named message with Content-Type: message/rfc822. Metadata includes containerId, sourceItemKey, containerRevisionHash, contentHash, operation, direction, sizeBytes, internalDate, and the flags seen, flagged, answered, draft, and deleted. A tombstone request ends after the metadata part.
Manifest version 1 uses UTF-8 and lowercase SHA-256 hex values. For each item, calculate:
leaf = sha256(sourceItemKey + NUL + operation + NUL + contentHash + NUL
+ decimalSizeBytes + NUL + direction + NUL + utcInternalDate + NUL
+ seen + NUL + flagged + NUL + answered + NUL + draft + NUL + deleted)Format utcInternalDate in UTC using RFC 3339 Nano. Encode Boolean values as the lowercase canonical text true or false. Opaque source identifiers must not contain U+0000 because NUL separates the fields. Sort the leaf hex values in ascending byte order, join them with LF, and hash the result with SHA-256. This is the folder's expectedManifestHash. For the batch, create one line per folder as containerRevisionHash:folderManifestHash:itemCount:byteCount; sort, join with LF, and hash those lines in the same way. An empty set is the SHA-256 digest of an empty byte sequence. The server persists source keys only as a keyed HMAC, while adapters can still calculate the public manifest digests independently.
Export a snapshot or delta
Export requires mail:export plus at least read access to the mailbox. POST /api/v1/mail/mailboxes/{mailboxID}/exports accepts fromRevision; use 0 for a complete snapshot. The response fixes throughRevision. Poll GET /api/v1/mail/exports/{exportID} until the job is completed and returns an artifactUrl. The encrypted nucleus-mail-transfer.v1 tar contains manifest.json and unchanged RFC822 files. Delta boundaries rely only on monotonic mailbox revisions, never timestamps.
The artifactUrl points to the protected mail endpoint GET /api/v1/mail/exports/{exportID}/artifact. Every download rechecks the requesting identity, mail:export, the current mailbox ACL, and the expiry time. Never copy exports into logs, tickets, or unprotected temporary storage.
The integration succeeds when an authorized client receives only its granted mailboxes and threads, an unauthorized request fails without content details, and the gateway removes a message from its queue only after 250 stored. For outbound mail, distinguish stored, queued, delivered, and DSN-failed recipient state.