Topolo Docs Topolo Platform
Open workspace

Run Mail assistant tool

Read or search mailbox content, generate a summary, reply suggestion or triage digest, or save an unsent draft.

Outcome

Read or search mailbox content, generate a summary, reply suggestion or triage digest, or save an unsent draft.

Before you start

  • Verify the intended environment, credential and authorized organization context before discovery.
  • Discover Mail, the exact action and its agent:use permission. Pass the accessible workspace resource binding separately from action input.
  • Review the actual change, recipients, provider/AI costs and any irreversible effects before confirmation; fixture IDs authorize no live operation.

Discover the target

  • Run credential-scoped Mail discovery and topolo workspaces list topolo-mail; select an authorized canonical workspace.
  • Resolve mailbox IDs through mailboxes.collection.list in that workspace. Resolve message, draft, thread, folder and scheduled IDs through the related published reads; never reuse fixture IDs or another context.
topolo whoami --json
topolo apps get topolo-mail --json
topolo actions get app_topolo_mail.agent.run --json
topolo workspaces list topolo-mail --json

Request

Create payload.json using the current input schema and discovered identifiers. Plan the unchanged request before execution.

topolo actions validate app_topolo_mail.agent.run --data @payload.json --json
topolo actions plan app_topolo_mail.agent.run --resource-type workspace --resource-id <discovered-workspace-id> --data @payload.json --confirm --json
topolo actions call app_topolo_mail.agent.run --resource-type workspace --resource-id <discovered-workspace-id> --data @payload.json --confirm --json

For MCP, use topolo_get_action, topolo_validate_action and topolo_plan_action; execute with topolo_call_action with confirm:true only after approval. Pass resourceType workspace and the discovered resourceId separately from input. An absent service/action or non-executable plan blocks that operation.

Input fields

FieldRequiredMeaning
mailboxIdYesMailbox ID from mailboxes.collection.list in the selected workspace; it is distinct from the workspace resource ID.
toolYesOne of read, search, summarize, suggest_reply, triage or draft. This action requires confirmation even for its read/search variants.
threadIdNoThread ID returned with a message in this mailbox. For agent read it is used when messageId is absent.
messageIdNoMessage ID returned by messages.list/get or threads.get in this mailbox.
originalMessageIdNoDiscovered original message ID for reply drafting or assistant thread lookup.
recipientNoOptional address/name to steer a reply suggestion; it does not send or automatically set recipients on a later draft.
queryNoNon-empty search text required by the assistant search tool.
folderIdNoFolder ID returned by folders.list in this mailbox; messages.move defaults to inbox when omitted.
toNoNon-empty array of approved recipient email addresses. Saving a draft does not authorize sending to them.
subjectNoReviewed message subject; non-empty for message/draft payloads, optional summary snapshot for snooze.
bodyTextNoPlain-text body; the handler prefers it to text for message sending and draft composition.

Effects

  • read/search request mailbox tool reads. summarize/suggest_reply/triage send bounded thread content to metered Nexus generation.
  • draft saves a mailbox draft. No tool in this action sends email; a human must review generated text and recipients before a separate send.

Interpret the response

read returns a message or thread collection; search returns matches. summarize returns summary, suggest_reply returns bodyText, and triage returns triage/count/model. draft returns a draft with HTTP 201. read needs messageId or threadId; search needs query; summary/reply need a non-empty resolved thread. recipient steers a suggestion and does not send anything. Triage examines up to 30 inbox messages, selects up to 25 unread (or all when none unread) and may return count 0 without AI generation.

Worked requests and responses

Successful fixture request · read · HTTP 200

Input

{
  "mailboxId": "mbx_mail_fixture",
  "tool": "read",
  "messageId": "msg_mail_fixture"
}

SDK response or error

{
  "success": true,
  "data": {
    "id": "msg_mail_fixture",
    "threadId": "thr_mail_fixture",
    "folderId": "inbox",
    "direction": "inbound",
    "subject": "Fixture status",
    "sender": "sender@example.test",
    "recipients": [
      "fixture@example.test"
    ],
    "date": "2026-10-08T00:00:00.000Z",
    "bodyText": "Synthetic content for handler capture.",
    "read": false,
    "starred": false,
    "attachments": []
  }
}

Supported variant · search · HTTP 200

Input

{
  "mailboxId": "mbx_mail_fixture",
  "tool": "search",
  "query": "fixture"
}

SDK response or error

{
  "success": true,
  "data": [
    {
      "id": "msg_mail_fixture",
      "threadId": "thr_mail_fixture",
      "folderId": "inbox",
      "direction": "inbound",
      "subject": "Fixture status",
      "sender": "sender@example.test",
      "recipients": [
        "fixture@example.test"
      ],
      "date": "2026-10-08T00:00:00.000Z",
      "bodyText": "Synthetic content for handler capture.",
      "read": false,
      "starred": false,
      "attachments": []
    }
  ]
}

Supported variant · summarize · HTTP 200

Input

{
  "mailboxId": "mbx_mail_fixture",
  "tool": "summarize",
  "messageId": "msg_mail_fixture"
}

SDK response or error

{
  "success": true,
  "data": {
    "tool": "summarize",
    "model": "fixture-completion",
    "threadId": "thr_mail_fixture",
    "messageId": "msg_mail_fixture",
    "subject": "Re: Fixture status",
    "summary": "Synthetic AI suggestion for review.",
    "threadMessageCount": 1
  }
}

Supported variant · suggest_reply · HTTP 200

Input

{
  "mailboxId": "mbx_mail_fixture",
  "tool": "suggest_reply",
  "messageId": "msg_mail_fixture",
  "recipient": "recipient@example.test"
}

SDK response or error

{
  "success": true,
  "data": {
    "tool": "suggest_reply",
    "model": "fixture-completion",
    "threadId": "thr_mail_fixture",
    "messageId": "msg_mail_fixture",
    "subject": "Re: Fixture status",
    "bodyText": "Synthetic AI suggestion for review.",
    "threadMessageCount": 1
  }
}

Supported variant · triage · HTTP 200

Input

{
  "mailboxId": "mbx_mail_fixture",
  "tool": "triage"
}

SDK response or error

{
  "success": true,
  "data": {
    "tool": "triage",
    "triage": "Synthetic AI suggestion for review.",
    "model": "fixture-completion",
    "count": 1
  }
}

Supported variant · draft · HTTP 201

Input

{
  "mailboxId": "mbx_mail_fixture",
  "tool": "draft",
  "to": [
    "recipient@example.test"
  ],
  "subject": "Synthetic fixture",
  "bodyText": "Synthetic content for review."
}

SDK response or error

{
  "success": true,
  "data": {
    "id": "draft_created_fixture",
    "threadId": "thr_mail_fixture",
    "folderId": "drafts",
    "direction": "draft",
    "subject": "Synthetic fixture",
    "sender": "sender@example.test",
    "recipients": [
      "recipient@example.test"
    ],
    "date": "2026-10-08T00:00:00.000Z",
    "bodyText": "Synthetic content for review.",
    "read": false,
    "starred": false,
    "attachments": []
  }
}

Refused requests

Unauthenticated caller · read · HTTP 401

Input

{
  "mailboxId": "mbx_mail_fixture",
  "tool": "read",
  "messageId": "msg_mail_fixture"
}

SDK response or error

{
  "code": "auth_error",
  "status": 401,
  "message": "Fixture authentication refused"
}

Service HTTP body

{
  "success": false,
  "error": {
    "message": "Fixture authentication refused"
  }
}

Permission denied · read · HTTP 403

Input

{
  "mailboxId": "mbx_mail_fixture",
  "tool": "read",
  "messageId": "msg_mail_fixture"
}

SDK response or error

{
  "code": "permission_denied",
  "status": 403,
  "message": "TopoloMail permission denied"
}

Service HTTP body

{
  "success": false,
  "error": {
    "message": "TopoloMail permission denied"
  }
}

Other organization · read · HTTP 403

Input

{
  "mailboxId": "mbx_mail_fixture",
  "tool": "read",
  "messageId": "msg_mail_fixture"
}

SDK response or error

{
  "code": "permission_denied",
  "status": 403,
  "message": "Mailbox does not belong to your organization"
}

Service HTTP body

{
  "success": false,
  "error": {
    "message": "Mailbox does not belong to your organization"
  }
}

Other verified workspace · read · HTTP 404

Input

{
  "mailboxId": "mbx_mail_fixture",
  "tool": "read",
  "messageId": "msg_mail_fixture"
}

SDK response or error

{
  "code": "http_error",
  "status": 404,
  "message": "Mailbox not found"
}

Service HTTP body

{
  "success": false,
  "error": {
    "message": "Mailbox not found"
  }
}

Verify the result

  • For reads, compare selected mailbox/message/thread IDs. For AI output, review claims and intended recipient against source messages; model output is a suggestion.
  • For draft, use messages.get on the returned ID and verify recipients/content before drafts.send.

Recover

Read and generated suggestions have no email recall step. An unsent draft can be reviewed or separately changed/deleted using its returned ID. Inspect state before repeating draft creation; do not duplicate drafts or regenerate paid output automatically.

  • HTTP 401 auth_error: Authenticate again in the intended environment and context, then repeat identity and action discovery.
  • HTTP 403 permission_denied: Stop for the exact permission, organization, sender or Reply-To refusal. Do not broaden access or switch credentials automatically.
  • HTTP 404 http_error: Rediscover the exact mailbox and child IDs in the same authorized workspace; do not guess another ID.

The captured SDK errors preserve the service code when structured, otherwise http_error and HTTP status. Do not invent a more specific code. Preserve the live request ID and inspect actual diagnostics for uncaptured failures.

Evidence and limits

  • Actual exported Mail handler dispatcher, widget handler, domain handlers, SDK transport/projection and shipped SQLite control/delivery/tracking migrations.

  • Identity, permissions, verified workspace grants, provider connection state, OAuth URL generation, mailbox Durable Object operations and content protection are synthetic ports.

  • Nexus AI and Auth archive are allowlisted in-process responses. No paid generation, billing, live OAuth, encryption custody, email delivery, asynchronous delivery or deployed outcome is proved. External network egress is refused.

The captured requests use synthetic identities and .test recipients. They demonstrate handler and SDK response behavior; they do not authorize delivery, provider consent, paid generation, deletion or other live effects. Current catalog discovery and environment proof remain separate release requirements.