postbus-mcp
postbus-mcp
Самостоятельно развертываемый MCP сервер позволяет вам и нескольким людям из вашего окружения работать с вашими почтовыми ящиками из Claude или любого другого MCP-клиента: искать, читать целые переписки и отправлять письма.
Работает с любым IMAP/SMTP-провайдером — Gmail, Outlook, Fastmail, вашим собственным почтовым сервером — с помощью обычного пароля приложения. Никакого проекта Google Cloud, никакой проверки OAuth, никакого ограничения тестовых пользователей.
Один экземпляр обслуживает несколько пользователей. Каждый получает собственный 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
Как это работает
Мультитенантный, но компактный. Один файл SQLite с двумя таблицами: users (id и хеш API-токена) и mail_accounts (почтовые ящики каждого пользователя, с зашифрованным паролем приложения). Никакой отдельной службы базы данных запускать не нужно.
Изоляция обеспечивается в запросе, а не последующей проверкой. Каждая MCP-сессия принадлежит ровно одному пользователю, который определяется bearer-токеном. MCP-сервер строится для каждого запроса вокруг этого пользователя, и каждый запрос к базе данных несет user_id в своем WHERE. Чужой алиас просто не существует в вашей сессии.
Интерфейс провайдера. Слой инструментов общается с универсальным MailProvider и ничего не знает об IMAP или Gmail. ImapSmtpProvider — основная реализация, а рядом опционально доступен GmailApiProvider. Добавление третьего не требует изменений в инструментах — см. Добавление провайдера.
Быстрый старт
С помощью 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 (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"}, что удобно для проверки доступности.
Пользователи и токены
Токены выдаете вы сами; самостоятельной регистрации нет.
Команда | Что делает |
| Создает пользователя и выводит токен (один раз) |
| Показывает пользователей, количество ящиков и статус |
| Новый токен; старый перестает работать сразу |
| Удаляет пользователя и все его почтовые ящики |
В 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"
]
}
}
}Этот файл находится по пути ~/Library/Application Support/Claude/claude_desktop_config.json на macOS и %APPDATA%\Claude\claude_desktop_config.json на Windows. Перезапустите 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>. Сервер работает без состояния — ни идентификаторов сессий, ни серверного потока — поэтому GET /mcp намеренно возвращает 405.
Привязка почтового ящика
Вы делаете это в диалоге, со своим токеном. Терминал не нужен:
Привяжи мой Gmail как "личный", адрес souf@gmail.com, пароль приложения abcd efgh ijkl mnop
Затем Claude вызывает add_mail_account. Сначала проверяется соединение (и IMAP, и SMTP); ничего не сохраняется, пока оба не заработают.
Создание пароля приложения
Провайдер | Где | Примечание |
Gmail / Workspace | Требуется 2FA на аккаунте | |
Outlook / Microsoft 365 | Требуется 2FA; администратор может заблокировать IMAP | |
Fastmail | Настройки → Конфиденциальность и безопасность → Пароли приложений | Выберите "Mail (IMAP/SMTP)" |
iCloud | https://account.apple.com → Пароли для приложений | Требуется 2FA |
Свой сервер | н/д | Ваш почтовый пароль или отдельный аккаунт |
Никогда не используйте обычный пароль, если провайдер предлагает пароли приложений.
Хост и порт
Для известных провайдеров postbus-mcp подставляет эти значения сам — вы указываете только алиас, email и пароль приложения:
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 явно.
Доступные инструменты
Инструмент | Что делает |
| Перечисляет ваши почтовые ящики с алиасом и email-адресом |
| Привязывает IMAP/SMTP-ящик с паролем приложения (сначала проверяет соединение) |
| Отвязывает ящик и удаляет сохраненный пароль приложения |
| Ищет по синтаксису в стиле Gmail; возвращает |
| Полное содержимое одного сообщения: заголовки, тело, метаданные вложений |
| Все сообщения переписки, от старых к новым |
| Отправляет новое сообщение сразу (cc, bcc, reply-to, html) |
Каждый инструмент работает только с почтовыми ящиками, принадлежащими пользователю, стоящему за токеном.
Синтаксис поиска
search_emails использует синтаксис в стиле Gmail. Для почтовых ящиков Gmail ваш запрос передается в Gmail без изменений (через X-GM-RAW), так что все, что работает в поисковой строке Gmail, работает и здесь. Для других IMAP-серверов он транслируется:
Термин | Gmail | Другой IMAP |
| ✅ | ✅ |
| ✅ | ✅ |
| ✅ | ✅ |
| ✅ | ✅ |
| ✅ | ✅ |
| ✅ | ✅ (фильтруется после) |
| ✅ | ✅ (через SPECIAL-USE) |
| ✅ | ✅ |
| ✅ | ⚠️ один объединенный текстовый термин |
| ✅ | ❌ игнорируется |
Примеры:
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 использует его, чтобы получить всю переписку — в хронологическом порядке, с отправителем, темой, датой и телом каждого сообщения.
Это происходит двумя способами, в зависимости от того, что умеет сервер:
Серверы Gmail (
X-GM-THRID) и RFC 8474 (OBJECTID) сами выдают стабильный идентификатор цепочки. Мы используем его напрямую, иthreadIdвыглядит какsrv:1829384756.Все остальные IMAP-серверы не имеют понятия цепочек. В этом случае мы восстанавливаем переписку из стандартных заголовков
Message-ID,In-Reply-ToиReferences: первый идентификатор в этой цепочке — корень цепочки. Такие значения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"На что обратить внимание:
Задайте
PUBLIC_HOSTв.envравным вашему собственному домену; это единственное место, где фигурирует домен, поэтому сам compose-файл остается нетронутым.Сеть
proxyдолжна существовать (docker network create proxy), и Traefik должен быть в ней.Контейнер не публикует ни одного своего порта: до него может добраться только Traefik.
TRUST_PROXY=trueпозволяет Express доверять заголовкамX-Forwarded-*.Терминируйте TLS на Traefik. Токены передаются как bearer-учетные данные; без HTTPS они передаются в открытом виде.
Том
postbus-dataсодержит базу данных со всеми зашифрованными паролями приложений. Делайте резервную копию вместе сMASTER_KEY— храните их раздельно.
Безопасность
MASTER_KEY. Пароли приложений и refresh-токены хранятся с использованием AES-256-GCM, каждый со своим IV. Сервер отказывается запускаться без ключа. Потеряете его — и всем придется заново привязывать свои почтовые ящики, поэтому храните его отдельно от резервной копии базы данных.
Токены. Хранится только SHA-256 хеш. Передавайте их по каналу, которому доверяете, и при сомнениях делайте ротацию (npm run rotate-token).
Изоляция. Каждый запрос к mail_accounts фильтруется по user_id, а MCP-сервер создается для каждого запроса вокруг одного пользователя, поэтому нет хранилища сессий, которое могло бы перепутать людей.
Чем это не является. Никакого ограничения частоты запросов, никакого журнала аудита, никаких детальных разрешений. Это предназначено для нескольких знакомых вам людей и работает под TLS. Не открывайте его для неизвестной аудитории.
Добавление провайдера
Слой инструментов взаимодействует только с MailProvider из src/types.ts:
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>;
}Провайдер получает полностью разрешенный аккаунт с расшифрованными учетными данными. Поиск алиаса происходит в слое инструментов, поэтому провайдер не может выйти за пределы пользователя сессии.
Чтобы добавить новый:
Расширьте
ProviderIdи объединениеMailAccountвsrc/types.ts.Напишите
src/providers/<name>/provider.tsс классом, реализующим интерфейс.Добавьте одну строку в карту в
src/providers/registry.ts.Убедитесь, что аккаунт такого типа может быть сохранен в базе данных: метод
save<Name>Account()вsrc/db/accounts.ts(секреты проходят черезencryptSecret), а также способ его привязки — дополнительный инструмент рядом сadd_mail_accountили CLI-скрипт.
Существующие инструменты (search_emails, get_message, get_thread, send_email) не требуют изменений. См. также CONTRIBUTING.md.
Опционально: Gmail через API вместо IMAP
В репозитории есть второй провайдер, который обращается к Gmail через Gmail API, а не через IMAP/SMTP. Он почти никогда не понадобится — IMAP с паролем приложения делает то же самое с гораздо меньшими формальностями. Он полезен только тогда, когда ваша организация блокирует IMAP, но разрешает API.
Создайте проект на https://console.cloud.google.com.
API и сервисы → Библиотека → найдите «Gmail API» → Включить.
API и сервисы → Экран согласия OAuth → укажите тип Внешний → заполните название и адрес поддержки.
Добавьте адреса, которые планируете привязать, в раздел Тестовые пользователи.
Учётные данные → Создать учётные данные → OAuth-идентификатор клиента → укажите тип Приложение для ПК.
Поместите идентификатор клиента и секрет в
.env:GOOGLE_CLIENT_ID=xxxxxxxxxxxx.apps.googleusercontent.com GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxxxxxxxxxxxxxx OAUTH_CALLBACK_PORT=53682Привяжите почтовый ящик. Это выполняется на машине администратора, потому что 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 находится в режиме Тестирование, refresh-токены истекают через 7 дней, и привязку нужно выполнять заново. Это прекращается только после перевода экрана согласия в режим В продакшене, что для этих областей требует проверки 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/ выполняются за полсекунды и не касаются ничего за пределами процесса: SQLite работает в памяти, и ни одно соединение не покидает машину. Они покрывают логику, которая может тихо сломаться, — преобразование поисковых запросов, кодирование идентификаторов сообщений и цепочек, разбор и сборку MIME, зашифрованное хранилище, разделение между пользователями и промежуточное ПО для bearer-токенов.
Чего они не покрывают — так это взаимодействие с реальным почтовым сервером. Для этого запустите 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 по производственным зависимостям, тесты и docker-сборку, которая запускает контейнер и проверяет, что /health отвечает, а /mcp возвращает 401 без токена. И CI, и контейнер работают на Node 24, текущей LTS.
Структура проекта
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.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables 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
- AlicenseBqualityBmaintenanceEnables 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.14MIT
- AlicenseAqualityBmaintenanceMCP server that enables email management (send, read, search, delete, etc.) via IMAP/SMTP, compatible with Gmail, Outlook, Yahoo, iCloud, and other standard mail servers.11MIT
- AlicenseNot gradedqualityAmaintenanceExposes any IMAP mailbox and SMTP relay as MCP tools, enabling email management (read, search, send, delete) through MCP-compatible agents.MIT
Related MCP Connectors
Read, search, send, organize, draft and schedule email across your inboxes from any MCP client.
Hosted email MCP for AI agents with inboxes, send/receive, memory, recovery, and credits.
Fully-managed email as MCP tools - register domains, real mailboxes, send and receive mail.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/HalloSouf/postbus-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server