feat(sim-mailer): email inbox for mothership with chat history and plan gating#3558
feat(sim-mailer): email inbox for mothership with chat history and plan gating#3558waleedlatif1 merged 21 commits intofeat/mothership-copilotfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryHigh Risk Overview Implements end-to-end inbox execution and replies. Adds an inbox executor that claims tasks, resolves/creates chats, runs the orchestrator with persisted chat messages, optionally fetches attachment metadata, and replies via AgentMail with rendered HTML; includes inbox lifecycle helpers to provision/teardown inboxes + webhooks. Exposes configuration and UI with plan/flag gating. Adds workspace APIs to enable/disable/regenerate inbox addresses, manage allowed senders, and list inbox tasks; adds a new Settings Written by Cursor Bugbot for commit 4997216. Configure here. |
e8fcad2 to
861215b
Compare
Greptile SummaryThis PR introduces Sim Mailer — a full email-to-task pipeline that lets workspace members send emails to an AgentMail-provisioned inbox, have the Mothership orchestrator process them, and receive a formatted reply. The feature includes the complete backend pipeline (webhook handler, executor, lifecycle, response), a settings UI with plan gating, React Query hooks, database schema, and a Trigger.dev background task. The implementation is thorough and incorporates many fixes identified in prior review rounds — Svix HMAC signature verification, atomic task claiming, JSONB-level chat message appends, enum-validated status filters, cursor validation, HTML sanitisation with code-fence awareness, Remaining issue:
Minor:
Confidence Score: 4/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant Sender as Email Sender
participant AM as AgentMail
participant WH as Webhook Handler<br/>/api/webhooks/agentmail
participant DB as Database
participant TD as Trigger.dev
participant EX as Inbox Executor
participant GO as Go Mothership<br/>/api/mothership/execute
participant RE as Response Sender
Sender->>AM: Send email
AM->>WH: POST webhook (Svix HMAC-SHA256)
WH->>DB: Lookup workspace by inbox_id + webhook secret
WH->>WH: Verify Svix signature
WH->>DB: Check duplicate (emailMessageId)
WH->>DB: isSenderAllowed (lower(user.email))
WH->>DB: getRecentTaskCount (excl. rejected)
WH->>DB: Lookup parent chatId (via responseMessageId)
WH->>DB: INSERT mothershipInboxTask (status=received)
WH->>TD: tasks.trigger(mothership-inbox-execution)
TD->>EX: executeInboxTask(taskId)
EX->>DB: Early exit if completed/failed
EX->>DB: Atomic claim (UPDATE WHERE status=received)
EX->>DB: resolveUserId (senderEmail → workspace member)
EX->>EX: formatEmailAsMessage
EX->>GO: orchestrateCopilotStream
GO-->>EX: OrchestratorResult
EX->>DB: JSONB append chat messages (atomic)
EX->>RE: sendInboxResponse
RE->>AM: replyToMessage
AM-->>Sender: Response email
EX->>DB: UPDATE task (status=completed, responseMessageId)
|
apps/sim/app/workspace/[workspaceId]/settings/components/inbox/inbox-enable-toggle.tsx
Show resolved
Hide resolved
|
@greptile |
|
@cursor review |
|
@greptile |
|
@cursor review |
|
@greptile |
|
@cursor review |
|
@cursor review |
|
@greptile |
apps/sim/app/workspace/[workspaceId]/settings/components/inbox/inbox-task-list.tsx
Show resolved
Hide resolved
- Exclude rejected tasks from rate limit count to prevent DoS via spam - Strip raw HTML from LLM output before marked.parse to prevent XSS in emails - Track responseSent flag to prevent duplicate emails when DB update fails after send
- Use dynamic isHosted from feature-flags instead of hardcoded true - Atomic JSON append for chat message persistence (eliminates read-modify-write race) - Handle cutIndex === 0 in stripQuotedReply (body starts with quote) - Clean up orphan mothershipInboxWebhook row on enableInbox rollback - Validate status query parameter against enum in tasks API
…ping - Validate cursor date before using in query (return 400 for invalid) - Split on fenced code blocks before stripping HTML tags to preserve code examples in email responses
…emove-sender errors - Guard against null result.content in stripThinkingTags - Use encodeURIComponent on all AgentMail API path parameters - Surface handleRemoveSender errors to the user instead of swallowing
…ptimistic ID collision Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nt flag, prevent inbox enumeration - Replace manual HMAC-SHA256 verification with official Svix library per AgentMail docs - Fix responseSent flag: only set true when email delivery actually succeeds - Return consistent 401 for unknown inbox and bad signature to prevent enumeration - Make AgentMailInbox.organization_id optional to match API docs
…→ 0173) Sync schema with target branch and regenerate migration as 0173 to avoid conflicts with 0172_silky_magma on feat/mothership-copilot.
… divergence Target branch added 0172_silky_magma, so our inbox migration is now 0173_youthful_stryfe.
87f7cb4 to
0355565
Compare
|
@greptile |
|
@cursor review |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
…s in email HTML - Use lower() in isSenderAllowed SQL to match workspace members regardless of email case stored by auth provider - Strip javascript:, vbscript:, and data: URIs from marked HTML output to prevent XSS in outbound email responses
|
@greptile |
|
@cursor review |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Consistent with the isSenderAllowed fix — uses lower() so mixed-case stored emails match correctly, preventing silent fallback to workspace owner.
|
@cursor review |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 3 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Summary
Adds the Sim Mailer feature — a complete email inbox system that allows users to email tasks to their workspace and have the mothership process them. This PR includes the full backend pipeline, settings UI, and several critical fixes for multi-turn email conversations.
Core Backend
app/api/webhooks/agentmail/route.ts) — receives inbound emails, validates senders, creates inbox tasks, and queues background execution via Trigger.devlib/mothership/inbox/executor.ts) — resolves user identity, manages chat lifecycle, runs the mothership orchestrator, persists messages, and sends response emailslib/mothership/inbox/format.ts) — strips quoted replies to avoid duplication, formats emails as mothership-compatible messages with attachment metadatalib/mothership/inbox/response.ts) — sends formatted HTML response emails via AgentMaillib/mothership/inbox/agentmail-client.ts) — typed wrapper around the AgentMail API for mailbox/message operationslib/mothership/inbox/lifecycle.ts) — mailbox provisioning, webhook registration, address updates, and teardownChat History Fix
messages: [{ role: 'user', content }](array) tomessage: content(singular string) to match the interactive copilot flowmessage(singular) is sent with achatId, the Go service loads the full conversation history from thechatstable viarepository.Load(). The previousmessagesarray approach caused Go to extract only the last message and discard history contextSettings UI
settings/components/inbox/) with five components:inbox.tsx— main component with Max plan gating and upgrade promptinbox-enable-toggle.tsx— toggle to enable/disable the inbox with mailbox provisioning modalinbox-settings-tab.tsx— email address display (read-only input with copy/edit tooltips matching sub-block pattern), allowed senders managementinbox-task-list.tsx— searchable, filterable task list with status badges, relative timestamps, and clickable tasks that navigate to/workspace/{id}/task/{chatId}inbox-skeleton.tsx— loading skeletons matching the actual layout structureInputfrom@/components/ui)h-3 w-3 text-muted-foregroundwith Tooltips)Plan Gating
getPlanTierCredits(plan) >= 25000 || isEnterprise(plan))useSubscriptionData({ enabled: isBillingEnabled }))Settings Infrastructure
scrollbar-gutter: stableto the settings layout to prevent content shift when filtering changes page heightInboxas a dynamic import insettings.tsxwithInboxSkeletonloading fallbackinboxtoSettingsSectiontype and navigation items withMailiconDatabase
inbox_enabled,inbox_address,inbox_provider_idcolumns toworkspacetablemothership_inbox_tasktable with indexes on(workspace_id, created_at),(workspace_id, status),email_message_id, andresponse_message_idmothership_inbox_allowed_sendertable with unique index on(workspace_id, email)mothership_inbox_webhooktable for webhook secret management0172_glossy_miek.sqlFeature Flags
INBOX_ENABLED(server) +NEXT_PUBLIC_INBOX_ENABLED(client) following the established dual env var pattern (same as SSO, credential sets, access control)hasInboxAccess()server-side check inlib/billing/core/subscription.tsBug Fix
chatIdvariable scoping inexecutor.tscatch block — was declared insidetrybut referenced incatch, causing error response emails to lose chat associationReact Query
hooks/queries/use-inbox.ts— query key factory withinboxKeys, hooks for config, tasks, senders, and mutations for toggle, address update, sender add/removestaleTime,signalforwarding, and proper cache invalidationType of Change
Testing
Tested manually — sent emails, verified multi-turn conversation context, tested plan gating, verified task navigation to chat view, tested search/filter, copy/edit tooltips, scrollbar stability.
Checklist