goshen-email README

The project's README from github.com/boringcomputers/goshen-email. As one markdown file: README.md.

Goshen Email

Email inboxes for AI agents. Each agent gets a real address, threads, attachments, and an API key that reaches only its own mail. People see the same mail in a dashboard, where they can reply, check delivery, and release quarantined messages.

Hosted service · Documentation · API reference · Contributing · License

The dashboard showing an agent's inbox with an open conversation

What it does

How it fits together

flowchart LR
  agent["Agent or app"] -->|"API key or MCP"| api["API Worker"]
  person["Person"] --> dashboard["Dashboard"]
  dashboard --> api
  api --> db[("PostgreSQL through Hyperdrive")]
  api --> r2[("R2: raw mail and attachments")]
  api <-->|"managed domains"| cloudflare["Cloudflare Email Routing and Sending"]
  api <-->|"custom domains"| gateway["SMTP gateway: Postfix, Rspamd, ClamAV"]
Path Contents
apps/email The API, a Cloudflare Worker. It stores mailboxes, sends and receives mail, and serves the REST API, the older RPC API, and hosted MCP.
apps/email-dashboard The dashboard, homepage, and docs site. It runs as a Cloudflare Worker, or as a Node server for local or VPS hosting.
apps/email-web A redesigned dashboard on Pluto's design system. It calls the dashboard's /api routes, holds no credentials, and is not deployed yet.
apps/email-gateway The SMTP gateway for domains at any DNS provider, packaged with Docker.
packages/email-client Private API client shared by the CLI and MCP server. Not published.
packages/email-cli Command-line client that prints JSON.
packages/email-mcp MCP server over stdio.
ops/email The gateway's Docker Compose, Caddy, and Rspamd configuration, plus reviewed SQL for the hosted database.
ops/autumn Plan definitions for hosted billing.
docs Operator guides and the OpenAPI document.

Try it locally

You need Node.js 24 and pnpm 10.15.1. The local fixture runs the API and the dashboard against an in-memory PostgreSQL database (PGlite). Routing, domain checks, sending, and file storage are test doubles, so you need no accounts or credentials, and no mail leaves your machine.

git clone https://github.com/boringcomputers/goshen-email.git
cd goshen-email
pnpm install --frozen-lockfile
pnpm build
pnpm --filter @bezalel/email exec tsx test/dashboard-fixture.ts

Open http://127.0.0.1:3038/app and sign in with the fixture password, fixture-dashboard-password-fixture-dashboard-password-. Create an inbox with the username hello, then deliver a message to it from a second terminal:

curl -X POST http://127.0.0.1:3039/receive \
  -H 'Content-Type: application/json' \
  -d '{"inboxId":"[email protected]","subject":"Hello from the fixture"}'

The message appears in the inbox. Mail you send or reply with from the dashboard stays inside the fixture; curl http://127.0.0.1:3039/sends lists it. The fixture listens on loopback only. Don't deploy it.

Self-host

Goshen Email runs on Cloudflare. A deployment needs:

apps/email/wrangler.jsonc and apps/email-dashboard/wrangler.jsonc contain the hosted service's account ID, resource IDs, routes, and domains. Replace them with your own before you deploy. The Worker guide lists the API Worker's settings. In the dashboard's file:

  1. Set up the API Worker with the Worker guide. It covers the Cloudflare account, secrets, R2, and queues.
  2. Create the database and connect Hyperdrive with the database guide. Put a direct connection string in apps/email/.env as DATABASE_URL and run pnpm migrate. It applies the full schema and is safe to rerun on upgrades.
  3. Pick a dashboard. The Cloudflare Worker dashboard supports public passwordless accounts; follow the account guide. The Node dashboard below uses one shared owner password and can see every inbox, so use it only for a single operator.
  4. For customer domains, deploy the SMTP gateway with its runbook.
  5. Deploy with pnpm deploy:worker, then pnpm deploy:dashboard. Deploy the API first, because a newer dashboard calls operations an older API rejects.

Triage needs a TypeSafe API key. Billing uses Autumn and Stripe; without AUTUMN_SECRET_KEY the API runs unmetered.

The CI workflow in this repository deploys the hosted service when a commit lands on main. In a fork, remove the deploy job from .github/workflows/ci.yml or point it at your own Cloudflare secrets.

Run the Node dashboard

cp apps/email-dashboard/.env.example apps/email-dashboard/.env
openssl rand -hex 32

Save the generated value as DASHBOARD_PASSWORD. Set MAIL_WORKER_URL to your API Worker's HTTPS origin and MAIL_API_TOKEN to its platform token. Don't reuse the token as the password.

pnpm build
pnpm start

Open http://127.0.0.1:3031/app. The Worker token stays on the dashboard server. Sessions expire after eight hours, signing out revokes them, and a restart signs everyone out.

To serve it remotely, put it behind an HTTPS reverse proxy that preserves the Host header, and set DASHBOARD_PUBLIC_URL to the exact public origin. Set HOST=0.0.0.0 if the proxy runs outside the dashboard's container. List the proxy's IP addresses in DASHBOARD_TRUSTED_PROXY_IPS and have the proxy overwrite X-Real-IP with the client's IP, so login throttling applies per client. Requests from a trusted proxy without a valid X-Real-IP can't sign in.

Use the API

Create a key under API keys in the dashboard, then:

export GOSHENEMAIL_BASE_URL="https://api.goshenemail.com"   # or your own API Worker
export GOSHENEMAIL_API_KEY="bze_..."

curl "$GOSHENEMAIL_BASE_URL/v1/inboxes" \
  -H "Authorization: Bearer $GOSHENEMAIL_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"username":"research","displayName":"Research agent"}'

The quickstart continues with sending and reading replies. The developer guide covers the CLI and MCP. The CLI and the stdio MCP server aren't on npm yet, so build them from this checkout.

The project started inside Bezalel. The internal workspace packages (@bezalel/email, @bezalel/email-dashboard, @bezalel/email-gateway) and the account key prefix bze_ keep names from that time.

Development

Command What it does
pnpm build Builds every package. The Workers build with Wrangler dry runs, so nothing deploys.
pnpm check Type-checks the workspace and fails if generated API files or docs are stale.
pnpm test Runs every package's tests on PGlite with test doubles for Cloudflare, R2, and SMTP.
pnpm test:postgres Runs the API tests through the production PostgreSQL driver. Needs TEST_DATABASE_URL; see the database guide.
pnpm source:check Checks files extracted from Bezalel against the hashes in SOURCE.json.
pnpm api:generate Regenerates the OpenAPI document, client types, and CLI and MCP schemas after a contract change.
pnpm docs:generate Rebuilds the docs site from apps/email-dashboard/docs/ and the OpenAPI document.
pnpm dev Starts the Node dashboard with file watching on port 3031.
pnpm dev:worker Starts the API Worker locally on port 8788. It needs a local PostgreSQL database.

Local tests can't prove live delivery, DNS, Cloudflare routing, Hyperdrive, R2, queues, or cron. The SMTP runbook's deployment canary checks those against a real deployment.

Documentation

The public docs at goshenemail.com/docs cover the API from an agent developer's side. The guides here cover running it.

Guide Covers
Worker setup Cloudflare setup, secrets, delivery tracking, suppression, quarantine, and failure handling
Database PostgreSQL, Hyperdrive, migrations, and local databases
SMTP gateway Customer domains, Postfix, Rspamd, ClamAV, TLS, and deployment canaries
Accounts Passwordless sign-up and sign-in
Cloudflare Access Optional invitation-only sign-in
Developer tools API keys, REST, CLI, and MCP
RPC API The older RPC interface, mailbox provisioning, and webhooks
Inbox setup The first-inbox flow for new accounts
Settings Organization, profile, and notification settings
Triage Categories, needs-reply, urgency, and what data leaves the Worker
Pricing Hosted plans and Autumn billing
Dashboard UX and design system Dashboard behavior and visual tokens
Web app The Pluto-design dashboard: local runs, checks, and rollout

The native-*, verification, and evidence files in docs/ record the hosted deployment's releases and the original extraction.

Where it came from

Goshen Email began as the email service inside Bezalel, a private Boring Computers project. SOURCE.md records the extracted revision and how fixes move between the two projects.

Contributing and security

Read CONTRIBUTING.md before opening a pull request. Report vulnerabilities privately as described in SECURITY.md, never in a public issue. Everyone taking part follows the code of conduct.

License

Goshen Email uses the Functional Source License 1.1 with an Apache 2.0 future license, FSL-1.1-ALv2. You can use, modify, and self-host it for any purpose, including inside a business. You can't offer it, or anything built from it, in a commercial product or service that competes with Goshen Email. Each release becomes available under Apache 2.0 two years after we publish it.

We published earlier commits under AGPL-3.0-only, and copies taken from them keep that license.

goshen-email (boringcomputers/goshen-email)

Searching Database…

这是什么?Goshen Email 为 AI 智能体提供真实的电子邮件收件箱,每个收件箱都有自己的地址、会话线程、附件和作用域受限的 API 密钥;同时还有一个面向人的仪表板,让人可以阅读同样的邮件、回复并放行被隔离的邮件。
这是一个库,还是一项托管服务?它是一项托管服务(也可在 Cloudflare 上自托管),围绕一个包含 17 个操作的 REST API 构建;CLI 和 MCP 服务器封装了相同的操作,没有单独的 SDK。
我怎么试用它?安装 Node.js 24 和 pnpm 10.15.1,然后运行本地 fixture,它会基于内存版 PostgreSQL(PGlite)启动 API 和仪表板,无需真实凭据也不会发送外发邮件。真正自托管则需要部署 API Worker、通过 Hyperdrive 连接 PostgreSQL 数据库,并选择一个仪表板。
真正自托管它需要什么?一个配置了 Email Sending/Routing 的 Workers Paid 套餐 Cloudflare 账号、一个可通过 Cloudflare Hyperdrive 访问的 PostgreSQL 数据库、一个带投递队列和死信队列的 R2 存储桶;如果要自定义域名,还需要一台允许 25 端口 SMTP 的服务器。
安装上有什么坑吗?CLI 和 stdio MCP 服务器尚未发布到 npm,所以你必须从源码检出中构建它们;许可证还禁止把本项目或基于它构建的任何东西作为竞争性商业邮件服务提供。
智能体之间的 API 密钥隔离性如何?账号级密钥可以在你授予的权限范围内访问该账号下的所有收件箱,而邮箱级密钥只能访问一个收件箱;这两种密钥都不能放行隔离邮件或创建其他密钥。
Bezalel 是什么?Bezalel 是 Goshen Email 从中抽出的 Boring Computers 内部项目;内部包名至今仍沿用当时的 bze 键前缀和 @bezalel scope。
它如何阻止自定义域名上的垃圾邮件和恶意软件?SMTP 网关会检查 SPF、DKIM 和 DMARC,用 Rspamd 和 ClamAV 扫描邮件,并把垃圾邮件、认证失败或含恶意软件的邮件扣留在隔离区,直到有人手动放行。
分诊(triage)功能是做什么的?可选的分诊功能会为新邮件标注类别、是否需要回复以及紧急程度评分,使用 TypeSafe API 密钥。
重试时它如何避免重复发送邮件?每次发送都需要幂等键,因此用相同的键和内容重试一次超时的发送,绝不会产生第二封重复邮件。
Size
7 MB
Stars
167
Updated
CommitOct 11
Age
1mo
Commits · 90 Days