Skip to main content
Glama
HalloSouf

postbus-mcp

by HalloSouf

postbus-mcp

Code quality Docker License: MIT

セルフホスト型のMCPサーバーで、あなたと周囲の少数の人々がClaudeやその他のMCPクライアントからメールボックスを操作できるようにします。検索、会話全体の閲覧、メール送信が可能です。

任意のIMAP/SMTPプロバイダー(Gmail、Outlook、Fastmail、独自のメールサーバー)で動作し、通常のアプリパスワードを使用します。Google CloudプロジェクトもOAuth認証もテストユーザー制限も不要です。

1つのインスタンスで複数のユーザーを利用できます。各ユーザーは自分のAPIトークンを持ち、自分のメールボックスだけを閲覧できます。あなたがホストし、トークンを配布します。オープンなサインアップはありません。

Claude / MCP client
        │  Authorization: Bearer <token>
        ▼
   POST /mcp  ──►  postbus-mcp  ──►  SQLite (users + encrypted app passwords)
                        │
                        ├──►  IMAP  (imapflow)      search, read, threads
                        └──►  SMTP  (nodemailer)    sending

目次


Related MCP server: simple-email-mcp

仕組み

マルチテナントでありながら、小規模です。 1つのSQLiteファイルに2つのテーブルがあります。users(idとAPIトークンのハッシュ)とmail_accounts(各ユーザーのメールボックス。アプリパスワードは暗号化されています)。別途データベースサービスを実行する必要はありません。

分離は事後チェックではなくクエリに組み込まれています。 すべてのMCPセッションは、ベアラートークンによって決定される単一のユーザーに属します。MCPサーバーはリクエストごとにそのユーザーを中心に構築され、すべてのデータベースクエリはWHERE句にuser_idを含みます。他のユーザーのエイリアスは、あなたのセッションには存在しません。

プロバイダーインターフェース。 ツール層は汎用のMailProviderと通信し、IMAPやGmailについて知りません。ImapSmtpProviderが主な実装で、任意でGmailApiProviderを併用できます。3つ目を追加してもツールの変更は不要です。プロバイダーの追加を参照してください。


クイックスタート

Dockerを使用する場合(推奨)

git clone https://github.com/HalloSouf/postbus-mcp.git
cd postbus-mcp

cp .env.example .env
openssl rand -hex 32          # put the result in .env as MASTER_KEY

docker compose up -d --build
docker compose exec postbus node dist/cli/add-user.js "Soufiane"

この最後のコマンドはAPIトークンを一度だけ出力します。すぐに保存してください。

Node.js(22以降)をローカルで使用する場合

npm install
cp .env.example .env
openssl rand -hex 32          # put the result in .env as MASTER_KEY

npm run build
npm run add-user -- "Soufiane"
npm start

サーバーはhttp://localhost:3000/mcpで待ち受けます。GET /healthは{"status":"ok"}を返すため、稼働確認に便利です。


ユーザーとトークン

トークンは自分で配布します。セルフサービスの登録はありません。

コマンド

説明

npm run add-user -- "Name"

ユーザーを作成し、トークンを出力します(一度だけ)

npm run list-users

ユーザー、メールボックス数、ステータスを表示します

npm run rotate-token -- <id>

新しいトークンを発行します。古いトークンは即座に無効になります

npm run remove-user -- <id>

ユーザーとそのすべてのメールボックスを削除します

Dockerでは、同じスクリプトをnode dist/cli/<script>.jsとして実行します:

docker compose exec postbus node dist/cli/list-users.js
docker compose exec postbus node dist/cli/rotate-token.js WvDnhafdM5yQ

各トークンのSHA-256ハッシュのみが保存されるため、紛失したトークンを調べることはできません。代わりにローテーションしてください。


クライアントの接続

Claude Desktop

Claude Desktopはstdioで通信するため、間にmcp-remoteを挟みます。claude_desktop_config.json内:

{
  "mcpServers": {
    "postbus": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://mcp.example.com/mcp",
        "--header",
        "Authorization: Bearer pb_YOUR_TOKEN_HERE"
      ]
    }
  }
}

このファイルはmacOSでは~/Library/Application Support/Claude/claude_desktop_config.json、Windowsでは%APPDATA%\Claude\claude_desktop_config.jsonにあります。編集後はClaude Desktopを再起動してください。

Claude Code

claude mcp add --transport http postbus https://mcp.example.com/mcp \
  --header "Authorization: Bearer pb_YOUR_TOKEN_HERE"

その他のクライアント

Streamable HTTPに対応するクライアントなら何でも動作します。エンドポイントはPOST /mcp、トークンはAuthorization: Bearer <token>です。サーバーはステートレスで動作します(セッションIDもサーバーサイドストリームもありません)。そのためGET /mcpは意図的に405を返します。


メールボックスのリンク

これは会話の中で、自分のトークンを使って行います。ターミナルは不要です:

私のGmailを「個人用」としてリンクしてください。アドレスはsouf@gmail.com、アプリパスワードはabcd efgh ijkl mnop

その後、Claudeはadd_mail_accountを呼び出します。最初に接続がテストされ(IMAPとSMTPの両方)、両方が機能するまで何も保存されません。

アプリパスワードの作成

プロバイダー

場所

備考

Gmail / Workspace

https://myaccount.google.com/apppasswords

アカウントで2FAが必要

Outlook / Microsoft 365

https://account.microsoft.com/security

2FAが必要。管理者がIMAPをブロックする可能性あり

Fastmail

設定 → プライバシーとセキュリティ → アプリパスワード

「Mail (IMAP/SMTP)」を選択

iCloud

https://account.apple.com → App用パスワード

2FAが必要

独自サーバー

n/a

メールパスワード、または専用アカウント

プロバイダーがアプリパスワードを提供している場合は、通常のパスワードを使わないでください。

ホストとポート

既知のプロバイダーでは、postbus-mcpがこれらを自動入力します。エイリアス、メールアドレス、アプリパスワードを指定するだけで済みます:

Gmail、Google Workspace、Outlook、Hotmail、Microsoft 365、Fastmail、iCloud、Yahoo、Zoho、Proton(Bridge経由)。

それ以外の場合は、自分で指定してください:

imap_host: imap.yourdomain.com    imap_port: 993   (TLS)
smtp_host: smtp.yourdomain.com    smtp_port: 465   (TLS) or 587 (STARTTLS)

ポート993と465は最初のバイトからTLSを使用します。他のポートでは、サーバーが対応している場合にSTARTTLSが使用されます。その前提がサーバーに当てはまらない場合は、imap_secureまたはsmtp_secureを明示的に指定してください。


利用可能なツール

ツール

説明

list_accounts

エイリアスとメールアドレス付きでメールボックスを一覧表示します

add_mail_account

IMAP/SMTPメールボックスをアプリパスワードでリンクします(最初に接続をテストします)

remove_mail_account

メールボックスのリンクを解除し、保存されたアプリパスワードを消去します

search_emails

Gmailスタイルの構文で検索します。メッセージごとにidとthreadIdを返します

get_message

1件のメッセージの完全な内容: ヘッダー、本文、添付ファイルのメタデータ

get_thread

会話内のすべてのメッセージを古い順に返します

send_email

新しいメッセージをすぐに送信します(cc、bcc、reply-to、html対応)

すべてのツールは、トークンの背後にあるユーザーに属するメールボックスにのみアクセスします。


検索構文

search_emailsはGmailスタイルの構文を使用します。Gmailメールボックスの場合、クエリはそのままGmailに送信されるため(X-GM-RAW経由)、Gmailの検索バーで機能するものはすべてここでも機能します。他のIMAPサーバーの場合は翻訳されます:

検索語

Gmail

その他のIMAP

from:, to:, cc:, bcc:, subject:

✅

✅

is:unread, is:read, is:starred, is:answered

✅

✅

newer_than:7d, older_than:2w (d/w/m/y)

✅

✅

after:2026-01-01, before:2026/03/01

✅

✅

larger:5M, smaller:100k

✅

✅

has:attachment

✅

✅ (後でフィルタリング)

in:inbox, in:sent, in:archive, in:all, in:trash

✅

✅ (SPECIAL-USE経由)

-from:someone (除外)

✅

✅

"exact phrase" と通常の単語

✅

⚠️ 1つのテキスト語句に結合

label:, filename:, category:

✅

❌ 無視

例:

from:boss@company.com is:unread newer_than:7d
subject:"march invoice" has:attachment
in:sent to:client@example.com older_than:1m

空のクエリは、受信トレイの最新メッセージを返します。


スレッド

search_emailsのすべての結果にはthreadIdが含まれ、get_threadはそれを使って会話全体を取得します。時系列順で、メッセージごとに送信者、件名、日付、本文が含まれます。

これはサーバーの機能に応じて2つの方法で行われます:

  • Gmail(X-GM-THRID)とRFC 8474サーバー(OBJECTID) は安定したスレッドIDを自ら発行します。これを直接使用し、threadIdはsrv:1829384756のようになります。

  • その他のIMAPサーバーにはスレッドの概念がありません。そこでは、標準のMessage-ID、In-Reply-To、Referencesヘッダーから会話を再構築します。そのチェーン内の最初のIDがスレッドのルートです。これらのthreadIdはref:で始まります。

取得時には、サーバーに「all mail」フォルダーがあればそこを検索し、なければInbox、Sent、Archiveを横断して検索します。そのため、自分が送信した返信も会話に含まれます。


Traefikの背後へのデプロイ

このリポジトリのdocker-compose.ymlは動作する例です。その核心部分:

services:
  postbus:
    build: .
    restart: unless-stopped
    environment:
      MASTER_KEY: ${MASTER_KEY:?set MASTER_KEY in .env}
      DATABASE_PATH: /data/postbus.db
      TRUST_PROXY: "true"
    volumes:
      - postbus-data:/data
    networks: [proxy]
    labels:
      traefik.enable: "true"
      traefik.docker.network: proxy
      traefik.http.routers.postbus.rule: Host(`${PUBLIC_HOST:-mcp.example.com}`)
      traefik.http.routers.postbus.entrypoints: websecure
      traefik.http.routers.postbus.tls.certresolver: letsencrypt
      traefik.http.services.postbus.loadbalancer.server.port: "3000"

注意すべき点:

  • .envのPUBLIC_HOSTを自分のホスト名に設定します。ドメインが現れるのはそこだけなので、composeファイル自体は変更不要です。

  • proxyネットワークが存在し(docker network create proxy)、Traefikがそのネットワーク上にある必要があります。

  • コンテナは独自のポートを公開しません。Traefikだけが到達できます。

  • TRUST_PROXY=trueを設定すると、ExpressがX-Forwarded-*ヘッダーを信頼します。

  • TLSはTraefikで終端します。トークンはベアラー資格情報として送信されるため、HTTPSがないと平文でやり取りされます。

  • postbus-dataボリュームには、暗号化されたすべてのアプリパスワードを含むデータベースが保存されます。MASTER_KEYは別に保管し、データベースと一緒にバックアップしてください。


セキュリティ

MASTER_KEY。 アプリパスワードとリフレッシュトークンは、それぞれ独自のIVを持つAES-256-GCMで保存されます。サーバーはキーがないと起動を拒否します。キーを失うと全員がメールボックスを再リンクする必要があるため、データベースのバックアップとは別に保管してください。

トークン。 SHA-256ハッシュのみが保存されます。信頼できるチャネルで共有し、疑わしい場合はローテーションしてください(npm run rotate-token)。

分離。 mail_accountsに対するすべてのクエリはuser_idでフィルタリングされ、MCPサーバーはリクエストごとに単一のユーザーを中心に構築されるため、人を取り違える可能性のあるセッションストアはありません。

これが提供しないもの。 レート制限も監査ログも細かい権限もありません。これはTLSの背後で、知り合いの数人を対象に構築されています。不特定多数に公開しないでください。


プロバイダーの追加

ツール層はsrc/types.tsのMailProviderとのみ通信します:

interface MailProvider<A extends MailAccount = MailAccount> {
  readonly id: ProviderId;
  verify(account: A): Promise<void>;
  search(account: A, query: string, maxResults: number): Promise<MessageSummary[]>;
  getMessage(account: A, messageId: string): Promise<MessageDetail>;
  getThread(account: A, threadId: string): Promise<MessageDetail[]>;
  send(
    account: A,
    to: string,
    subject: string,
    body: string,
    options?: SendOptions,
  ): Promise<string>;
}

プロバイダーは完全に解決されたアカウントを受け取り、資格情報は復号化されています。エイリアスの検索はツール層で行われるため、プロバイダーはセッションのユーザーの外部にアクセスできません。

追加する手順:

  1. src/types.tsのProviderIdとMailAccountユニオンを拡張します。

  2. インターフェースを実装するクラスを含むsrc/providers/<name>/provider.tsを作成します。

  3. src/providers/registry.tsのマップに1行追加します。

  4. そのタイプのアカウントがデータベースに到達できるようにします。src/db/accounts.tsにsave<Name>Account()を追加し(シークレットはencryptSecretを経由)、さらにリンクする手段(add_mail_accountの隣に追加のツールを置くか、CLIスクリプト)を用意します。

既存のツール(search_emails、get_message、get_thread、send_email)は変更不要です。CONTRIBUTING.mdも参照してください。


オプション: IMAPの代わりにAPI経由でGmailを使用

このリポジトリには、IMAP/SMTP ではなく Gmail API 経由で Gmail にアクセスする第 2 のプロバイダが含まれています。これを使う必要はほぼありません。アプリパスワードを使った IMAP で同じことを、はるかに少ない手間で実現できるからです。このプロバイダが役立つのは、組織が IMAP をブロックしているが API は許可している場合だけです。

  1. https://console.cloud.google.com でプロジェクトを作成します。

  2. APIs & Services → Library で "Gmail API" を検索し、Enable をクリックします。

  3. APIs & Services → OAuth consent screen で External を選択し、名前とサポートメールアドレスを入力します。

  4. 連携予定のアドレスを Test users に追加します。

  5. Credentials → Create credentials → OAuth client ID で Desktop app を選択します。

  6. クライアント ID とシークレットを .env に記述します:

    GOOGLE_CLIENT_ID=xxxxxxxxxxxx.apps.googleusercontent.com
    GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxxxxxxxxxxxxxx
    OAUTH_CALLBACK_PORT=53682
  7. メールボックスを連携します。Google がコールバックを localhost に送信するため、これは管理者のマシンで実行します:

    npm run list-users                       # look up the user id
    npm run link-gmail -- <user-id> work

使用するスコープ: gmail.readonly、gmail.send、gmail.compose、gmail.labels。

注: OAuth 同意画面が Testing に設定されている間、リフレッシュトークンは 7 日 で期限切れになり、再連携する必要があります。この問題が解消されるのは、同意画面が In production に切り替わったときだけです。ただし、この切り替えには、これらのスコープでは Google の審査が必要です。まさにこれが、アプリパスワードを使った IMAP が主要な経路である理由です。


開発

npm install
npm run dev          # server with hot reload (tsx watch)
npm test             # unit tests (vitest)
npm run typecheck    # src + tests
npm run format       # prettier across the repo
npm run build        # into dist/

tests/ 内のテストは 0.5 秒で実行され、プロセスの外部には一切触れません。SQLite はインメモリで動作し、マシンの外への接続は発生しません。テストがカバーするのは、静かに失敗しうるロジック、つまり検索クエリの変換、メッセージ ID とスレッド ID のエンコード、MIME の解析と構築、暗号化ストレージ、ユーザー間の分離、ベアラーミドルウェアです。

テストがカバー しない のは、実際のメールサーバーとの通信です。それを行うには、GreenMail をローカルで実行してください:

docker run -d --rm --name greenmail -p 3143:3143 -p 3025:3025 \
  -e GREENMAIL_OPTS='-Dgreenmail.setup.test.imap -Dgreenmail.setup.test.smtp -Dgreenmail.users=souf:secret@postbus.test -Dgreenmail.hostname=0.0.0.0' \
  greenmail/standalone:2.1.0

次に、imap_host: 127.0.0.1、imap_port: 3143、smtp_host: 127.0.0.1、smtp_port: 3025、username: souf、app_password: secret を指定してメールボックスを連携します。

GreenMail は Gmail 拡張機能に対応していません。X-GM-RAW と X-GM-THRID を使用するコードの分岐は、実際の Gmail メールボックスに対してのみテストできます。

GitHub Actions は、すべての push と pull request で同じチェックを実行します: フォーマット、型、本番依存関係に対する npm audit、テスト、そしてコンテナを起動して /health が応答することと /mcp がトークンなしで 401 を返すことを検証する docker ビルドです。CI とコンテナはどちらも、現在の LTS である Node 24 で実行されます。

プロジェクト構成

src/
├── index.ts              startup: check MASTER_KEY, open the db, listen
├── config.ts             environment configuration
├── crypto.ts             AES-256-GCM for secrets, hashing for tokens
├── types.ts              MailProvider plus every shared type
├── db/                   SQLite: migrations, users, mail_accounts
├── http/                 Express app, bearer auth, MCP transport per request
├── providers/
│   ├── registry.ts       account -> provider
│   ├── imap/             IMAP/SMTP: connections, search, threading, sending
│   └── gmail/            optional Gmail API provider (OAuth)
├── tools/                the MCP tools (they know no provider)
└── cli/                  admin scripts: users and tokens

tests/                    unit tests (vitest), mirroring the layout of src/

ライセンス

MIT — LICENSE を参照してください。

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables reading and sending emails via IMAP and SMTP through the MCP protocol. Supports multiple email accounts and configuration via UI or environment variables.
    BSD 3-Clause
  • A
    license
    B
    quality
    B
    maintenance
    Enables users to manage email accounts via IMAP/SMTP, including reading, searching, sending emails with attachments and calendar invites, all through natural language interactions with MCP-compatible clients.
    1
    40 PyPI
    4
    MIT
  • A
    license
    B
    quality
    A
    maintenance
    Connects MCP clients to any IMAP/SMTP email account, enabling email search, reading, sending, replying, forwarding, flagging, moving, and folder management via natural language.
    17
    MIT
  • A
    license
    B
    quality
    C
    maintenance
    Enables email integration through MCP, including sending, receiving, searching, replying to, and forwarding emails, plus folder management and multi-account support with encrypted credential storage.
    40
    1,152 npm
    MIT