## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - Connections give agents controlled access to external services. > - Experimental channels already map conversations to tasks and durable work queues. > - Email needs inbox ownership, recipient envelopes, delivery records, and explicit sends. > - This pull request adds AgentMail to that infrastructure and keeps the provider key in the server vault. > - Agents can receive and send email from local or sandbox execution while the board follows each conversation in its task. ## Linked Issues or Issue Description **Problem or motivation** Agents need dedicated email addresses. Incoming email should become assigned work. Internal task comments and progress must never become outgoing email by accident. **Proposed solution** Add experimental AgentMail connections, an inbox assignment wizard, durable email intake and publication, task email cards, and authenticated API, CLI, and native runtime actions. Agents use Paperclip credentials to request sends. Paperclip owns the provider key and enforces access and task authority. **Alternatives considered** A general mailbox MCP connector does not provide durable task binding or publication boundaries. A separate mailbox application duplicates task collaboration. The board instead directs the agent through the normal task conversation. **Roadmap alignment** This extends the existing experimental connections and task infrastructure. Product scope and interaction design were reviewed with the maintainer. Related connection authority work: #11831 and #11818. The duplicate search found no competing task-based AgentMail integration. ## What Changed - Add AgentMail catalog data, shared contracts, company-scoped email records, and an additive migration. - Add vaulted setup, inbox assignment, access grants, trust guidance, and provider-side allowlist guidance. - Support WebSocket and signed-webhook intake through a shared durable pipeline, deduplication, catch-up, and task wakeups. - Queue explicit new conversations and replies with immutable send intents, idempotency, delivery state, and uncertain-send resolution. - Show inbound and outbound email cards in normal task conversations. Keep internal messages internal. - Add task-scoped CLI actions and the sandbox callback routes required for Daytona execution. - Provide a dedicated AgentMail skill automatically only to agents with active authorized inbox assignments. Keep email instructions out of the universal Paperclip skill. - Advertise connector-owned `agentmail_inboxes`, `agentmail_read_thread`, `agentmail_send`, and `agentmail_delivery` tools only in eligible native sessions. Recheck live authority on execution. - Isolate Codex CLI connector skills by agent and skill revision. Deliver the assigned skill in the run prompt for adapters that use shared skill directories, including resumed turns. Keep automatic skills out of manual persistent sync. Show them as read-only and document the pattern in the connector playbook. - Fix AgentMail health checks that entered local-stdio validation and optional missing Codex credential cleanup in sandboxes. - Add API, pipeline, authorization, sandbox, browser, and Storybook coverage. ## Verification - Live AgentMail testing covered WebSocket intake, signed webhooks, restart catch-up, and a full receive → task → Daytona Codex CLI → explicit reply → Delivered round trip. The reply was verified in the other inbox. The normal task composer also initiated an outgoing email child task. - The connector-skill change was verified in the browser: AgentMail appears once as an automatic, read-only skill with its assigned address. Disabling experimental chat connections removes it; re-enabling restores it. A regression test covers assignment data arriving after library data. - Connector regression coverage passed 178 runtime utility, email integration, skill-route, and heartbeat tests. All 17 Codex execution tests passed, including per-agent skill isolation, model identity, revision changes, removal, and prompt delivery without shared skill files. - After rebasing onto master, all 44 focused email, heartbeat, and native-authority tests passed. All 313 native-session executor tests passed. The UI regression suite passed all 3 tests. These test sets overlap earlier focused runs. - Full workspace typecheck and build passed after the rebase. Token gates passed. Earlier focused Playwright task/setup coverage and the Storybook build also passed. - Native connector tool execution uses deterministic integration tests. Live Daytona qualification used the Codex CLI adapter; the new shared-home prompt fallback has deterministic coverage. - The full repository suite is run by CI. The earlier unsharded local full-suite attempt was stopped after the equivalent CI suites passed and is not reported as a completed local run. Greptile reviewed `7e57dc267a8446d3c906e3cc5b8abc94fb8860eb` at 5/5 with no unresolved threads. All server, workspace, serialized server, and browser suites passed in CI. The build job hit a five-second timeout in a runner transport test; both variants and the full 80-test file passed locally with unchanged timeouts. The build passed on retry on the same commit without code or timeout changes. All required CI gates, including the final `ci / verify` and `ci / e2e` summaries, are green on `7e57dc267a8446d3c906e3cc5b8abc94fb8860eb`. ## Risks - Email from external senders can start normal agent work. Setup recommends a low-trust agent and AgentMail sender controls. Sender addresses never grant board membership. - Provider timeouts can leave uncertain sends. Retries retain their idempotency key; expired windows require reconciliation or operator resolution. - Connector skills and native tools are assignment-dependent and require current access. Revocation denies retained calls; assignment changes select a new runtime context. - Activation remains behind the experimental-channel setting. The native runner path has deterministic coverage; live Daytona qualification used the Codex CLI adapter. - Schema changes are additive. Inbox ownership is unique across companies. Disconnect preserves provider inboxes and task history. ## Model Used OpenAI GPT-6 (Codex). Used reasoning, repository tools, code execution, and browser testing. The exact deployment model ID and context-window size were not exposed in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
7.8 KiB
AgentMail verification — 2026-09-11
Environment
Worktree: codex/agentmail. The original checkout and its merge conflicts were
preserved. Live checks used the isolated AgentMail Test Drive company at
http://localhost:3103, with the experimental connections feature enabled.
Only these user-authorized inboxes exchanged test mail:
- Paperclip:
pap15838-qa@agentmail.to, assigned to Email QA. - Other end:
attractiveforce961@agentmail.to, inspected in AgentMail Console.
Live browser results
| Journey | Observed result |
|---|---|
| Connect from the Apps catalog | Saved personal human access, selected agent access, and a vaulted key through the real UI. |
| Give an agent an address | Used Permissions → three-step wizard → existing scoped inbox. The selected agent, review warnings, and connection persisted. |
| Trust controls | Saved Low-trust review with a root-task boundary, verified the missing-sandbox prerequisite, then explicitly restored Standard for this local QA agent. |
| Live receiving | Inbound correspondence created AGE-6. The agent explicitly replied once; the reply appeared in AgentMail Console and Paperclip recorded Delivered. |
| Signed webhook | Registered an inbox-scoped webhook. Actual signed POSTs returned 204. AGE-7 received its email, the agent replied once, and both consoles showed the exchange. |
| Reply to a completed conversation | New mail reused the same task and reopened it. |
| Restart catch-up | Sent another reply while the server health endpoint was unreachable. Startup imported it into AGE-7, woke the agent, and sent one acknowledgement in the same thread. |
| Agent-initiated new conversation | A board request in AGE-7 caused the agent to create AGE-8 with parentId pointing to AGE-7. One email was sent and marked Delivered; it appeared as a separate thread in AgentMail Console. |
| Internal publication boundary | Internal summaries and the outbound-only child task's “No reply sent” response produced no additional emails. |
| Cleanup | Restored WebSocket mode, removed Paperclip's test webhook, stopped the webhook-only proxy/tunnel, and removed the temporary public URL from the isolated configuration. Inbox history and vaulted test credentials remain inspectable. |
Useful live pages:
- Saved connection permissions
- Inbox settings
- Inbound conversation and restart recovery: AGE-7
- Agent-created email child: AGE-8
- Other inbox in AgentMail Console
Timing
These are individual observations from email.received audit records, not a
load test or latency guarantee. Admission-to-wakeup includes durable processing
and heartbeat admission; it excludes provider delivery and subsequent model
startup/generation.
| Check | Admission to wakeup |
|---|---|
| Live inbound, AGE-6 | 409 ms |
| Signed webhook, AGE-7 | 421 ms |
| Startup catch-up, AGE-7 | 585 ms |
The clean webhook run was created at 18:10:53.471Z, started at
18:10:53.512Z, sent its reply at approximately 18:11:40Z, and finished at
18:12:05.225Z. Model work is separate from the sub-second admission measurement.
Fixes found by testing
- Personal credential access displayed as organization access in the generic connection panel. AgentMail now displays the actual saved grants and installs.
- Low-trust permissions used the wrong mutation route; Standard omitted rather than cleared the previous boundary. Both are fixed and covered by regressions.
- Email task recovery incorrectly entered restricted chat replay. Normal email work now uses normal task recovery while retaining execution controls.
- A send/read-only key could not register a webhook. Setup now explains the required inbox-scoped webhook permissions. A failed switch leaves the live connection active. The user authorized a replacement scoped key for the live webhook test.
- Graceful shutdown retained the socket lease until its crash timeout. Shutdown
now releases only this worker's socket tokens; the ownership test verifies
immediate takeover by a second worker. The final live restart became ready at
18:30:10Zand completed a mail check at18:30:14Z, with no connection error. - A path-like attachment filename could produce a stored object key that the storage reader rejected. Imported filenames now remove path traversal segments. The regression covers bounded, deduplicated intake, reading stored bytes, task-scoped attachment references, and rejecting bytes changed after queueing.
- The initial QA agent attempted to install the released CLI for an unreleased feature. The test agent now uses the local HTTP API. Runtime documentation also describes the direct HTTP fallback.
- The first QA instruction to leave work open omitted a valid task disposition, triggering existing recovery controls after a successful send. Corrected QA instructions explicitly set the requested disposition. Clean subsequent runs completed successfully; those earlier diagnostic tasks remain inspectable.
Automated verification
- API/provider and durable-pipeline tests: 32 passed, including signature checks, deduplication, callback-before-response, uncertain-send handling, inbox/company isolation, credentials, low-trust placement, and socket ownership/shutdown.
- OpenAPI contract checks passed (8 tests); the final combined run passed all 40.
- Deterministic Playwright setup and task-conversation coverage includes actual trust-permission persistence, rich email cards, and Bcc details. Following the board UX revision, email controls were removed and instructions use the normal task composer. Its provider responses are mocked; it is separate from the live browser results above.
- Trust UI tests passed (10 tests).
- Catalog regression and damaged-runner-history recovery regression passed.
- Repository typecheck and build passed; changed-package checks were repeated after subsequent fixes. Token gates and whitespace checks passed.
- Full repository Vitest run did not pass. The general server group finished with 10,584 passing tests, five failing tests, and one database-startup suite failure. Its five individual failures subsequently passed in focused reruns (email recovery/trust, gallery count, plugin wait, and damaged runner history). This broad run began before the final fixes; it is not a final green result.
- Additional broad workspace and serialized-route groups encountered database startup, hook, and adapter timeouts. The UI group had 5,923 passing tests and five failures; rerunning its two affected files passed all 73 tests. Shared contracts passed 727 tests and the skills catalog passed 20. Remaining broad groups have not been rerun to completion, so this is not a PR-ready all-green qualification.
Limits
The account was at its inbox limit, so live setup attached an existing inbox. Programmatic inbox creation and custom domains were not live-qualified. Attachment transfer, invalid signatures, cross-company denial, cancellation, duplicate callbacks, and expired idempotency windows are checked deterministically rather than against the live provider. Low-trust execution was not run in a real sandbox; setup correctly rejected the isolated test drive's missing sandbox runtime.
One restart-test acknowledgement arrived in the other inbox while Paperclip's status remained Sent because its delivery receipt was missed during socket recovery. Sent records provider acceptance; Paperclip does not fabricate a Delivered receipt or resend the message. The later independent outbound email received and recorded its Delivered receipt normally.