Mail workflows
Search multiple mail accounts, retrieve threads, and create reversible provider Drafts.
ctxindex presents Gmail and Outlook messages through the provider-neutral communication.message Profile. Each mailbox is a Source attached to one Account and one Realm, while search can span Sources and providers.
Search across accounts
First inspect the configured Sources and their Account bindings:
ctxindex account list --json
ctxindex source list --jsonSearch every configured mailbox by omitting --realm and --source:
ctxindex search "renewal notice" --kind mail --jsonRestrict a search to one operating context or mailbox when the task requires it:
ctxindex search "renewal notice" \
--kind mail \
--realm company \
--json
ctxindex search "flight receipt" \
--kind mail \
--source personal-gmail \
--jsonAn omitted Realm spans all Realms. --realm company is exact and never includes personal Sources implicitly. Gmail and Outlook mailbox Sources use provider search when routing requires it, but return the same result envelope and stable Ref shape.
To list recent unread mail without inventing query text, select one remote mailbox and use the Profile's exact boolean field. When the selected Adapter returns an opaque continuation, inspect pagination.hasMore and repeat the unchanged request. The current Microsoft mailbox Adapter supports this flow; Gmail returns no continuation and rejects a supplied token as invalid_filter before provider I/O:
ctxindex search --remote \
--source company-mail \
--kind communication.message \
--field unread=true \
--since 2026-07-01 \
--limit 50 \
--json
ctxindex search --remote \
--source company-mail \
--kind communication.message \
--field unread=true \
--since 2026-07-01 \
--limit 50 \
--continuation '<pagination.continuation>' \
--jsonunread=true and unread=false are exact booleans. Remote continuation cannot be combined with local --offset, and a truncated warning with a non-null continuation means more provider results are resumable. A truncation warning without a continuation is not resumable through --continuation.
Retrieve a message and its thread
Search for the message
ctxindex search "deployment approval" --kind mail --jsonRetrieve the complete message
ctxindex get 'ctx://01J00000000000000000000000/message/stable-message-id' --jsonLoad the related conversation
ctxindex thread get 'ctx://01J00000000000000000000000/message/stable-message-id' --jsonthread get follows stored conversation membership and parent Relations. It returns a reply tree when parent edges are available and otherwise a date-ordered list.
Create a provider Draft
A Draft is reversible provider state, not text that exists only in an agent conversation. Inspect the live Action schema before constructing input:
ctxindex action describe communication.message.draft.create \
--source company-mail \
--jsonCreate the Draft through the mailbox Source that should own it:
cat > /tmp/new-draft.json <<'JSON'
{
"to": ["recipient@example.com"],
"cc": ["reviewer@example.com"],
"subject": "Deployment follow-up",
"bodyText": "The deployment completed successfully."
}
JSON
ctxindex action run communication.message.draft.create \
--source company-mail \
--input /tmp/new-draft.json \
--jsonBoth Gmail and Outlook mailbox Adapters implement this Action. The result returns a normalized communication.message Resource Ref for the provider-persisted Draft.
Create a threaded reply Draft
A reply Action does not fetch missing parent data. First use get on the exact parent Ref so a complete, non-deleted message from the selected Source is available locally:
ctxindex get 'ctx://01J00000000000000000000000/message/stable-message-id' --jsonThen create the reply with the strict reply branch. It accepts only the local parent Ref and body text; ctxindex derives the single recipient, reply subject, and provider-native thread state from the parent:
cat > /tmp/reply-draft.json <<'JSON'
{
"replyToRef": "ctx://01J00000000000000000000000/message/stable-message-id",
"bodyText": "Thanks, I will review the deployment report today."
}
JSON
ctxindex action run communication.message.draft.create \
--source company-mail \
--input /tmp/reply-draft.json \
--jsonThe parent must belong to company-mail, be locally complete, and contain the provider threading fields. Reply-all and caller-supplied recipients or subject are intentionally unavailable.
Update an existing Draft
Inspect the current update union before constructing input:
ctxindex action describe communication.message.draft.update \
--source company-mail \
--jsonA standalone Draft update replaces the complete addressed content. Supply the Draft Ref returned by create or retrieval and the full desired recipient arrays, subject, and body. Empty cc and bcc arrays explicitly clear those recipients:
cat > /tmp/updated-draft.json <<'JSON'
{
"ref": "ctx://01J00000000000000000000000/draft/stable-draft-id",
"to": ["recipient@example.com"],
"cc": [],
"bcc": [],
"subject": "Updated deployment follow-up",
"bodyText": "The deployment and verification completed successfully."
}
JSON
ctxindex action run communication.message.draft.update \
--source company-mail \
--input /tmp/updated-draft.json \
--jsonReply context is immutable. Before updating a reply Draft, ensure both its Draft Ref and its parent message are complete local Resources in the same selected Source (Action results are already materialized; otherwise use get). The update must repeat the exact stored replyToRef and may replace only bodyText:
ctxindex get 'ctx://01J00000000000000000000000/draft/stable-draft-id' --json
ctxindex get 'ctx://01J00000000000000000000000/message/stable-message-id' --json
cat > /tmp/updated-reply-draft.json <<'JSON'
{
"ref": "ctx://01J00000000000000000000000/draft/stable-draft-id",
"replyToRef": "ctx://01J00000000000000000000000/message/stable-message-id",
"bodyText": "Thanks, I reviewed the deployment report."
}
JSON
ctxindex action run communication.message.draft.update \
--source company-mail \
--input /tmp/updated-reply-draft.json \
--jsonChanging replyToRef, using the standalone branch for a stored reply Draft, or supplying recipients or subject in the reply branch fails before provider I/O.
Provider mutations stop at reversible email Draft creation and update. ctxindex never sends email and exposes no send, reply-send, forward-send, calendar mutation, or other provider mutation.