yamail-mcp
README.md
<div align="center">
# 📬 yamail-mcp
**MCP-сервер для Яндекс Почты** — научите любого ИИ-агента
работать с вашей почтой: читать, искать, отвечать и отправлять
письма обычными словами прямо в чате.
[](https://www.python.org/)
[](https://modelcontextprotocol.io)
[](#-подключение-к-chatgpt)
[](LICENSE)
</div>
---
## ✨ Что это
Удалённый MCP-сервер, к которому **обычный ChatGPT подключается сам** —
как коннектор в настройках. Никакого «скопируй промпт в агента»: включил
Developer Mode, добавил URL, один раз ввёл код доступа — и в чате появляется
ваша почта.
| | |
|---|---|
| 📨 **14 инструментов** | чтение, поиск, отправка, ответ, пересылка, черновики, метки, удаление |
| 🔐 **OAuth 2.1** | authorization code + PKCE, регистрация клиента по DCR — подключение в два клика |
| 🪶 **35 МБ RAM** | один процесс, одна зависимость (Flask), IMAP/SMTP из stdlib |
| 🔒 **Ноль открытых портов** | Cloudflare Tunnel, TLS на краю, приложение слушает только localhost |
| 🌐 **Кириллица из коробки** | папки и поиск по-русски, темы и тела писем не ломаются |
```
ChatGPT ──OAuth 2.1──▶ yamail-mcp ──IMAP/SMTP──▶ imap.yandex.ru / smtp.yandex.ru
◀─JSON-RPC── (127.0.0.1) ▲
│
Cloudflare Tunnel ────────┘
(TLS на краю, порты не открыты)
```
## 📋 Содержание
- [Что умеет](#что-умеет)
- [Требования](#требования)
- [Установка](#установка)
- [Подключение к ChatGPT](#подключение-к-chatgpt)
- [Инструменты](#инструменты)
- [Примеры запросов](#примеры-запросов)
- [Тесты](#тесты)
- [Безопасность](#безопасность)
- [Важно про Яндекс OAuth](#важно-про-yandex-oauth)
- [Особенности реализации](#особенности-реализации)
- [Обслуживание](#обслуживание)
- [Связанные проекты](#связанные-проекты)
## 🎯 Что умеет
Чтение и поиск по всем папкам (входящие, отправленные, черновики, корзина,
спам, архив) с поддержкой кириллицы, чтение писем с вложениями, отправка,
ответ с сохранением цепочки, пересылка, черновики, перемещение, метки
прочитано/важное/звезда, удаление. Плюс пара инструментов `search`/`fetch` —
обёртка, без которой коннектор не работает в Deep Research.
## 📋 Требования
- Linux-сервер с Python 3.11+ (проверено на 3.12) и выходом в интернет
- Домен на Cloudflare для туннеля (или любой способ получить HTTPS на 443)
- Аккаунт Яндекс Почты с включённым IMAP
Зависимости: только `Flask`. IMAP, SMTP, криптография и разбор MIME — из
стандартной библиотеки.
## 🚀 Установка
### 1. Пароль приложения в Яндексе
У Яндекса **нет OAuth-скоупа для почты** (подробности ниже), поэтому единственный
способ — пароль приложения:
1. Открыть https://id.yandex.ru/security/apppasswords
2. «Создать пароль приложения», назвать как угодно
3. Скопировать выданный пароль
4. Отдельно убедиться, что IMAP включён: mail.yandex.ru → Настройки →
«Доступ по IMAP»
Пароль приложения не заменяет основной пароль и не даёт доступа к веб-интерфейсу.
Отзывается там же.
### 2. Файлы и конфиг
```bash
sudo mkdir -p /opt/yamail-mcp
sudo cp app.py mail.py oauth.py /opt/yamail-mcp/
sudo cp config.example.json /opt/yamail-mcp/config.json
sudo pip3 install 'Flask>=3.0,<4'
```
Заполнить `/opt/yamail-mcp/config.json`:
```json
{
"yamail_token": "любой-длинный-случайный-код",
"port": 5180,
"public_url": "https://yamail.example.com",
"address": "your-mailbox@yandex.ru",
"app_password": "пароль-из-шага-1",
"imap_host": "imap.yandex.ru",
"imap_port": 993,
"smtp_host": "smtp.yandex.ru",
"smtp_port": 465,
"oauth_clients": []
}
```
`yamail_token` — код, который вводится на экране согласия при подключении
ChatGPT. Сгенерировать можно так:
```bash
python3 -c "import secrets; print(secrets.token_urlsafe(24))"
```
Дальше — `chmod 600 /opt/yamail-mcp/config.json`.
### 3. Автозапуск
```bash
sudo cp yamail-mcp.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now yamail-mcp
curl -s http://127.0.0.1:5180/healthz
```
### 4. Доступ снаружи
Нужен HTTPS на 443 с валидным сертификатом. Обычный nginx + Let's Encrypt
не всегда подходит: порт 443 на сервере может быть занят, а каждому новому
хосту нужен свой сертификат. Cloudflare Tunnel решает оба вопроса и не
открывает портов вообще. Подробности и обязательные флаги для серверов с
капризной сетью — в [deploy/cloudflared.md](deploy/cloudflared.md).
## 🔗 Подключение к ChatGPT
1. Включить Developer Mode: https://platform.openai.com/docs/guides/developer-mode
2. ChatGPT → Settings → Connectors → Create
3. Заполнить:
- **Name** — например, «Яндекс Почта»
- **URL** — `https://yamail.example.com/mcp`
- **Auth** — `OAuth`
4. В чате: «+» или `@` → выбрать коннектор → **Sign in**
5. Откроется экран согласия — ввести `yamail_token` из конфига
6. Вернуться в ChatGPT, коннектор подключён
Сразу после подключения стоит зайти в Settings → Plugins → приложение →
Permissions и выбрать **«Всегда спрашивать»**: коннектор умеет отправлять
письма твоим именем, и по умолчанию лучше подтверждать каждое действие.
## 🧰 Инструменты
| Инструмент | Что делает |
|---|---|
| `unread_count` | Сколько всего и сколько непрочитанных. Ответ на «что нового?» |
| `list_folders` | Все папки с назначением. Первым делом, если что-то «не нашлось» |
| `search_emails` | Поиск. `query` — синтаксис IMAP: `ALL`, `UNSEEN`, `FROM "a@b.c"`, `SUBJECT "счёт"`, `SINCE 01-Dec-2025` |
| `read_email` | Полный текст письма и список вложений. Не помечает прочитанным |
| `send_email` | Отправка. Поддерживает cc, bcc, html |
| `reply_email` | Ответ с сохранением цепочки, `all_reply` — ответить всем |
| `forward_email` | Пересылка с исходным текстом |
| `create_draft` | Черновик без отправки |
| `move_email` | Переместить в другую папку |
| `mark_email` | Прочитано/не прочитано, флаги «важное» и «звезда» |
| `delete_email` | В Корзину; `expunge: true` — безвозвратно. Требует `confirm: true` |
| `search` / `fetch` | Обёртка для Deep Research: поиск и полный текст по `id` |
| `verify_connection` | Проверка IMAP/SMTP и счётчики. Первое, что стоит звать, если что-то не работает |
Идентификатор письма — строка вида `папка|uid`, например `INBOX|41703`.
Её возвращает `search_emails` и её же нужно передавать обратно в остальные
инструменты; после перемещения письма идентификатор меняется, поэтому
устаревший `id` даёт понятную ошибку, а не молчаливый «успех».
Папки можно называть по-русски или по-английски: `INBOX`/«Входящие»,
`Sent`/«Отправленные», `Drafts`/«Черновики», `Trash`/«Корзина»,
`Junk`/«Спам», `Archive`/«Архив».
## 💬 Примеры запросов
- «Что нового в почте?»
- «Найди непрочитанные от hr@company.ru за последнюю неделю»
- «Что в последнем письме от банка?»
- «Подготовь ответ: подтверждаю, спасибо» — создаст **черновик**, не отправляя
- «Отправь письмо vasya@mail.ru с текстом…»
- «Перешли последнее письмо о счёте в бухгалтерию»
- «Перемести все рассылки от рекламы в Корзину»
## 🧪 Тесты
Два независимых теста. Токен в обоих — из переменной окружения, в коде его нет.
```bash
# протокол: OAuth-цикл, PKCE, 401/WWW-Authenticate, tools/list, кэш и ротация
# токенов, revoke. Почту не трогает.
YAMAIL_TOKEN=<код> python selftest.py https://yamail.example.com
# боевая проверка на живом ящике. По умолчанию только чтение.
YAMAIL_TOKEN=<код> python live_check.py https://yamail.example.com
# добавить проверку записи (создаёт черновик и письмо самому себе)
YAMAIL_TOKEN=<код> YAMAIL_ADDRESS=your-mailbox@yandex.ru \
python live_check.py https://yamail.example.com --write
```
`selftest.py` — 61 проверка, закрывает весь OAuth-цикл, который повторит
ChatGPT, включая негативные случаи.
## 🔐 Безопасность
| Что | Как |
|---|---|
| Доступ к MCP | OAuth 2.1: authorization code + PKCE (S256), токены 12 ч, refresh 90 дней с ротацией |
| Клиенты | DCR — ChatGPT регистрируется сам; вручную описанные клиенты — в `oauth_clients` |
| Экран согласия | Требует `yamail_token`, независимо от того, кто пришёл |
| Пароль почты | Только в `config.json` с правами 600, никогда не попадает в ответы и логи |
| Поверх сети | Cloudflare Tunnel, наружу с 443, порты не открыты, TLS на краю |
| Опасные действия | `delete_email` требует `confirm: true`; защиту подтверждает ChatGPT, а не сервер |
| Случайные токены | Клиент регистрируется сам; старые клиенты и коды подчищаются |
Про выданные токены: `/oauth/sessions` по тому же `yamail_token` показывает
счётчик активных токенов. Токен можно отозвать через `/oauth/revoke`
или удалив `oauth.json` и перезапустив сервис.
Про браузерный доступ: в зоне Cloudflare должен быть выключен Browser
Integrity Check — он отвечает `403 (1010)` на небраузерные User-Agent, а
ChatGPT ходит с бот-агентом. Проверено: `curl` проходит, `Python-urllib`
получает 403.
## ⚠️ Важно про Яндекс OAuth
Часто встречается совет «сделать OAuth 2.1 с обменом токенов по RFC 8693,
чтобы ИИ ходил в почту по токену Яндекса». **Это невозможно**, и вот почему:
- Яндекс OAuth поддерживает ровно два `grant_type`: `authorization_code`
и `refresh_token`. Обмен токенов (RFC 8693) не реализован.
- Скоупа `mail:imap` / `mail:smtp` у Yandex ID **не существует** вообще.
Есть `login:*` и API отдельных сервисов (Диск, Календарь, Переводчик).
Поэтому XOAUTH2 для личной Яндекс Почты невозможен в принципе.
Следствие: сервер не хранит и не проксирует токен Яндекса. Он хранит
**пароль приложения** и работает по IMAP/SMTP. Свой OAuth 2.1 нужен только
для того, чтобы сам ChatGPT мог подключиться к этому серверу, — и это
единственная роль, которую он здесь играет.
Сервисные приложения Яндекс 360 (для организаций с собственным доменом) —
отдельная история, они требуют прав администратора организации.
## 🧠 Особенности реализации
Три места, где пришлось повозиться, и почему так:
**Имена папок приходят в modified-UTF7.** Яндекс отдаёт `&BBAEQARFBDgEMg-`
вместо «Архив». Реализован декодер/кодер по RFC 3501. На провод уходит
исходная форма, человеку — читаемая.
**Поиск по кириллице требует `CHARSET UTF-8`.** Без него `SEARCH` отвечает
`NO` вместо результата — молча, без ошибки. Критерий с не-ASCII
автоматически отправляется с `CHARSET UTF-8`.
**IMAP-соединение переиспользуется.** Яндекс отвечает на приветствие нового
соединения с задержкой, которая после серии частых подключений доходит до
30 секунд. Все команды после `LOGIN` при этом выполняются за миллисекунды.
Поэтому держится одно соединение, а папка выбирается повторно только при
смене. Первый вызов после запуска может быть медленным, дальше — доли секунды.
## 🛠 Обслуживание
```bash
systemctl status yamail-mcp
journalctl -u yamail-mcp -f
tail -f /opt/yamail-mcp/yamail.log # лог приложения
systemctl restart yamail-mcp
```
Логи: `yamail.log` с ротацией, 1 МБ × 2. Ошибки почты возвращаются клиенту
как `isError` с понятным текстом, а не как HTTP 500.
Если сменишь пароль приложения — поправь `config.json` и перезапусти сервис.
## 🔗 Связанные проекты
Другие MCP-коннекторы для тех же ИИ-агентов:
- 🛒 [**pyaterochka-mcp-tool**](https://github.com/dreamcatchered/pyaterochka-mcp-tool) — MCP-сервер и AI-бот для каталога «Пятёрочки»: магазины, товары, акции и цены по всей России. Первый коннектор, с которого всё началось.
- 📬 [**dreamMail**](https://github.com/dreamcatchered/dreamMail) — пересылка новых писем по IMAP в Telegram.
## 📄 Лицензия
MIT — можно использовать и дорабатывать свободно.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues