Skip to content

Manage retained Mail

Trash, restore, sender blocking, suppression feedback and export.

Trash, restore, and purge

Use the same saved credentials and a message ID returned by mail list. Replace MESSAGE_ID below with that ID:

agent-workplace mail trash MESSAGE_ID --json
agent-workplace mail list --view trash --json
agent-workplace mail restore MESSAGE_ID --json

Members can trash and restore their own messages. Owners/admins can also explicitly select another permitted Mailbox with --mailbox MAILBOX_ID and permanently purge trashed content. Purge requires the message to be in trash. Human dashboard viewing does not provide these management controls.

To permanently remove a trashed message, an authorized owner or administrator can run agent-workplace mail purge MESSAGE_ID --json. Purge cannot be undone.

Trash remains counted and restorable for seven days from the original trash action; repeating trash does not extend that deadline. Purge or expiry removes retained content and frees its body-storage bytes. Incoming usage is not refunded. Trash stops further sending submissions and cancels definitively unstarted sends. Restore never resumes sending. Already-started sends still require reconciliation; none of these commands promises recall or a sending refund.

Success returns { "acknowledged": true } for the local action. Commands never retry these mutations automatically. If a response is lost, inspect mail list, mail list --view trash, or mail read MESSAGE_ID before deciding the next action. A missing message does not prove your earlier request succeeded, and another session may change state after inspection. A repeated purge of missing content returns not_found. Local send-operation files and copies already obtained by clients or external recipients are not removed by these commands.

The SDK exposes trashMailMessage, restoreMailMessage and purgeMailMessage, with optional { mailboxId }. The corresponding POST routes end in /v1/mail/messages/{messageId}/trash, /restore, and /purge; send an empty JSON object for the acting account's Mailbox, or { "mailboxId": "..." } for explicit authorized targeting. These routes use the existing Mail API enablement gate.

Prospective sender blocking

Use mail block-sender <address> and mail unblock-sender <address> to set an exact From-address rule in your Mailbox. Use --mailbox <id> only for a Mailbox you can administer. mail blocked-senders lists current rules with --limit and --after; restart a live listing to include rules inserted before an existing cursor. SDK methods are blockMailSender, unblockMailSender and listMailSenderBlocks.

Blocked arrivals retain no new body or attachments and consume no incoming unit; mail omissions reports sender_blocked in the existing seven-day history. This does not promise the transport provider rejected or did not charge for the mail. Existing content is unchanged. Unblocking does not retrieve previously omitted mail, and replay never changes an already retained or omitted delivery.

Supply a bare address. Domain case is normalized; external local-part case and plus aliases stay distinct. Matching uses an unambiguous canonical From address, not Reply-To or display names, and is not sender authentication. The message From header takes precedence; the provider From field is used only when that header is absent. Ambiguous or omitted From headers do not fall back to a different field. Repeating an unchanged desired state is idempotent; opposite concurrent writes follow commit order, so retrying an older block/unblock request can change the current rule. The human interface displays omission reasons and remains read-only.

Provider suppression feedback

mail status and SDK getMailOperation expose receipt.suppressedAt when detailed history is available. It records provider suppression associated with this operation, without identifying affected recipients or declaring the entire message failed. Accepted usage is unchanged; an uncertain operation remains uncertain until independent evidence arrives. The server stops new attempts for that operation. Already running requests may still finish. Do not create a new send to bypass suppression.

Null means no suppression has been recorded; an absent field on an older server means the information is unavailable. Neither is evidence of recipient delivery. The read-only human message view shows the same observation while detailed history is available. Incoming spam assessment is unavailable from the integrated receiving contract; sender blocking and provider complaint feedback remain separate protections.

Export retained Mail

Agents can export a retained message, its currently known thread, or an authorized Mailbox through the SDK and CLI. This copies actual retained text, HTML and attachments plus metadata. It does not reconstruct an original MIME message, recover purged content or claim a complete external conversation.

mkdir -m 700 ./mail-export-state
agent-workplace mail export --mailbox MAILBOX_ID --scope message \
  --message MESSAGE_ID --output ./message-export \
  --operation ./mail-export-state/message.json --json

Use --scope thread --message MESSAGE_ID for the known conversation, or --scope mailbox without --message for the whole retained Mailbox, including trash, current pending-only preparations and omission history. The output must be a new directory with an existing parent. The operation file must be outside the output, in an existing directory owned by you with mode 0700. Recovery currently requires a POSIX filesystem. Export remains agent-facing; the human Mail interface is read-only.

The CLI first freezes a local inventory, then copies its pinned content. Repeat the same command, operation file and output after an interruption. Completed local bytes are checked and reused; unresolved attachments are acquired again under current authorization and must match the original identity, length and SHA-256. A later purge can prevent uncopied bytes from being obtained. Export never substitutes a newer part or overwrites an existing destination. An interrupted inventory is restarted with a fresh observation checkpoint; a completed inventory is not automatically refreshed. Use a new operation and destination after a completed inventory to discover new content or include attachments that became retained later. If discovery itself stops for thread indexing or conflict, retry the same command with a fresh inventory.

Recovery requires a saved local identity. If a crash occurs between creating an output/recovery directory or content candidate and saving its inode identity, the same command fails safely instead of adopting the unrecorded path. Keep any existing copies and use a new operation file and new output directory for a fresh export; do not edit receipts or remove existing files to force a retry. Bytes no longer retained at the source cannot be reacquired into that fresh export.

manifest-ATTEMPT.json records each attempt's outcome, counters and coverage. record-N.json preserves the frozen metadata in inventory order; attempt-ATTEMPT-N.json reports copy results for that record. Message text and HTML use generated message-ID.text/.html names; attachment bytes use attachment-ID.bin. Original filenames, content types and display metadata remain metadata, never local paths. Present-empty bodies produce empty files; absent and unknown representations stay distinct. Pending/omitted parts remain explicit. Hidden staging files and private operation storage are required for recovery; keep them together with the output until recovery is no longer needed.

Every export has coverage: "non_snapshot". mailboxChanges reports observed changes during the inventory/copy window, or unknown if history cannot establish coverage. state: "partial" covers failures, missing/duplicate discovery, pending preparations/parts, unknown body representations or unknown change coverage. Partial results are JSON on stdout with a nonzero exit and a diagnostic on stderr. Authorization loss stops further source acquisition; inspect stopped, per-record results and unattemptedRecords. Preserved omission metadata alone is not a failed copy of retained bytes. Download grants are temporary capabilities and are not saved in the export.

SDK consumers can iterate walkRetainedMail(auth, { mailboxId, scope }, visits). Provide a fresh asynchronous visits.addIfNew(key) store per traversal; large consumers should persist the opaque keys instead of retaining them in memory. The iterator yields inventory records with backpressure, not local files or attachment bytes. Use downloadMailAttachment for verified retained bytes. Thread incomplete and per-resource issues are distinct from completed enumeration; even a complete inventory does not prove that its bytes have been copied.

On this page