dsh-agentmail
用 AgentMail 给 agent 配一个自己的收件箱:发信、读信、搜索与打标签共十一个工具;收到的邮件按邮件线程分派,每个线程对应一个独立会话;所有外发邮件都要过审批与收件人白名单。
安装
dsh plugin --profile web add dsh-agentmail
沙箱测试
这个插件还没测过。提交测试 →
README
<p align="center">
<img src="https://raw.githubusercontent.com/agentmail-to/dsh-agentmail/main/assets/hero.svg" width="100%" alt="dsh-agentmail — an AgentMail plugin for DeepSeek Harness. Give an agent its own email inbox; inbound mail becomes one harness session per email thread." />
</p>
<p align="center">
<a href="https://www.npmjs.com/package/dsh-agentmail"><img src="https://img.shields.io/npm/v/dsh-agentmail?style=flat-square&labelColor=0A0A0A&color=3A3A3A" alt="npm" /></a>
<a href="tests"><img src="https://img.shields.io/badge/tests-74-3A3A3A?style=flat-square&labelColor=0A0A0A" alt="74 tests" /></a>
<a href="https://github.com/topics/dsh-plugin"><img src="https://img.shields.io/badge/dsh--plugin-topic-3A3A3A?style=flat-square&labelColor=0A0A0A" alt="dsh-plugin topic" /></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-3A3A3A?style=flat-square&labelColor=0A0A0A" alt="MIT license" /></a>
</p>
<p align="center">
<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>
</p>
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
Capability · MCP client · This plugin
Send, read and search tools · yes · yes
Inbound mail reaches the agent · no · yes
Bounces reported back, so a failed send isn't assumed delivered · no · yes
Approval gate and recipient allowlist on outbound · no · yes
Follow-ups that survive the conversation ending · no · yes
Inbox identity and untrusted-content rules in the system prompt · no · yes
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:
Entry · Injects · Role
dsh-agentmail/tools · tools · The model-facing tool surface
dsh-agentmail/identity · systemPrompt · Inbox identity and the untrusted-content rules
dsh-agentmail/approval · tools · Recipient allowlist + human approval on outbound
dsh-agentmail/inbound · agents · Inbound 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.
Tool · Notes
agentmail_list_inboxes ·
agentmail_create_inbox ·
agentmail_list_threads · Cursor-paged, label-filterable
agentmail_get_thread · Bodies truncated to maxBodyChars
agentmail_search · Relevance-ranked full text
agentmail_send_message · Idempotency-keyed on the tool call id
agentmail_reply · replyAll opt-in; idempotency-keyed
agentmail_create_draft · The human-in-the-loop path
agentmail_send_draft ·
agentmail_update_labels · Workflow state
agentmail_followup · Due-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:
Branch · When · What happens
live · an agent is already running · inject just the new message
persisted · a session log exists on disk · resume it, then inject the new message
fresh · neither · create it, and seed from threads.get(threadId)
The third branch is why there is no mapping store: AgentMail is the store. A session lost
to a restart, a cleared profile, or a different machine rebuilds itself from the API.
Consequences that are handled, and worth knowing:
- Concurrent mail on one thread hits an in-flight latch, so two messages arriving inside the
create window produce one session, not two.
- Idle disposal is non-destructive. Sessions idle past
idleDisposeMsare disposed with no
eviction ordering to reason about — the log survives, and the API can rebuild regardless.
maxLive is only a flood cap.
- Outbound-initiated threads start life in whatever session sent the first mail. When the
reply arrives, the new thread session seeds from the API, so it knows everything that was
said but not the sending session's private reasoning. Accepted for v1.
Set threadSessions.enabled: false to route all mail into one fallbackSessionId instead.
Follow-ups: why not schedule_create?
Harness Schedule reminders only fire while a session has a live root Agent, and the only
other thing that revives a thread session is inbound mail. But "follow up in 3 days if they
haven't replied" is precisely the case where no mail arrives — so a session-local reminder
would never fire.
`agentmail_followu
…(truncated)
以上内容来自 npm 上的 README,我们只做格式化,不改内容。
版本
npm 上共发布:1,最后更新 2026-08-18