DSH Hub

agentmail-to/dsh-agentmail

dsh-agentmail

BundleWorkflow1 GitHub stars· updated 2026-08-18

Give a DeepSeek Harness agent its own email inbox — inbound mail bound to one session per email thread. A dsh plugin.

Install

npx @deepseek-ai/dsh plugin --profile demo add dsh-agentmail

Restart `dsh web` after install. Bundle APIs can change during the developer preview.

README badge

dsh-agentmail DSH Hub badge
[![DSH Hub](https://dshhub.dev/badge/dsh-agentmail.svg)](https://dshhub.dev/plugins/dsh-agentmail)

Paste this into your README. The star count updates with every catalog sync.

From the README

Excerpt from agentmail-to/dsh-agentmail, cleaned of badges and images.

<a href="#two-ways-to-install">Install</a> · <a href="#tools">Tools</a> · <a href="#how-thread-binding-works">Thread binding</a> · <a href="#follow-ups-why-not-schedule_create">Follow-ups</a> · <a href="#security">Security</a> · <a href="#configuration">Config</a>

Two ways to install

The 5-minute on-ramp: the built-in MCP client

The harness ships @deepseek-ai/dsh-mcp-client, and AgentMail runs an MCP server. Zero code:

- id: mcp-agentmail
  name: '@deepseek-ai/dsh-mcp-client'
  config:
    serverName: agentmail
    transport: streamable-http
    url: https://mcp.agentmail.to/mcp
    headers:
      Authorization: !!js '`Bearer ${process.env.AGENTMAIL_API_KEY}`'

That gives you mcp__agentmail__send_message and friends today. It does not give you the four things below.

This plugin

export AGENTMAIL_API_KEY=...
dsh plugin --profile demo add dsh-agentmail   # or: add github:agentmail-to/dsh-agentmail#<sha>
dsh --profile demo
CapabilityMCP clientThis plugin
Send, read and search toolsyesyes
Inbound mail reaches the agentnoyes
Bounces reported back, so a failed send isn't assumed deliverednoyes
Approval gate and recipient allowlist on outboundnoyes
Follow-ups that survive the conversation endingnoyes
Inbox identity and untrusted-content rules in the system promptnoyes

Local development

npm install && npm run build
dsh web --patch ./cordis.patch.yml

What gets mounted

Four independent plugins, so a deployment can drop any one from its own patch layer:

EntryInjectsRole
dsh-agentmail/toolstoolsThe model-facing tool surface
dsh-agentmail/identitysystemPromptInbox identity and the untrusted-content rules
dsh-agentmail/approvaltoolsRecipient allowlist + human approval on outbound
dsh-agentmail/inboundagentsInbound mail, thread sessions, follow-up sweep

Tools

Eleven, curated rather than a mirror of the REST API — every registered schema is paid on every model request.

ToolNotes
agentmail_list_inboxes
agentmail_create_inbox
agentmail_list_threadsCursor-paged, label-filterable
agentmail_get_threadBodies truncated to maxBodyChars
agentmail_searchRelevance-ranked full text
agentmail_send_messageIdempotency-keyed on the tool call id
agentmail_replyreplyAll opt-in; idempotency-keyed
agentmail_create_draftThe human-in-the-loop path
agentmail_send_draft
agentmail_update_labelsWorkflow state
agentmail_followupDue-date label; wakes a cold thread session

Canonical returns are a programmatic API — ids and fields, never prose to re-parse — so Code Mode can drive batch triage through await tools.agentmail_list_threads(...) in one call.


How thread binding works

The session id is a total function of the thread id:

sessionId = "agentmail-" + threadId
flowchart LR
  M([inbound mail<br/>on thread T]) --> Q{"session<br/>agentmail-T ?"}
  Q -->|live| L[inject the new message]
  Q -->|persisted on disk| R[resume, then inject]
  Q -->|neither| C[create, then seed<br/>from the AgentMail API]
  L --> A([agent handling thread T])
  R --> A
  C --> A

Inbound mail on thread T takes one of three branches:

Related plugins