Proton Mail Bridge MCP
Connects to the Proton Mail Bridge, Proton's official local IMAP gateway for Proton Mail accounts, to read a mailbox via scoped tokens (proton.read, proton.attachments, proton.ablage). The Bridge can be deployed headlessly from Proton's signed Debian package inside Docker.
Read-only access to a Proton Mail mailbox through the official Proton Mail Bridge (IMAP). Provides tools to list mailboxes and labels, search emails (with working umlaut and multi-word matching over decoded headers), retrieve whole threads and individual messages (HTML reduced to text), fetch attachments as base64 or rendered PNG images for vision models, extract text from PDF attachments (PDF text layer or OCR), and store attachments into a shared drop folder without passing the raw bytes through the model. Never writes to the mailbox, uses BODY.PEEK so messages stay unread, and reports per-mail SPF/DKIM/DMARC authenticity.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Proton Mail Bridge MCPsearch my inbox for emails about Rechnung and show the latest thread"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Proton Mail Bridge MCP (read-only)
English · Deutsch
Unofficial. This project is not affiliated with, endorsed by or supported by Proton AG. „Proton“ and „Proton Mail“ are trademarks of Proton AG.
A read-only connector that lets AI agents read a Proton Mail mailbox through the official Proton Mail Bridge (IMAP). It provides an MCP server (Model Context Protocol, Streamable HTTP) and a few bulk export scripts on top of a shared read-only core.
Design principles
No write path to the mailbox. The core knows no method to send, delete, move, flag or tag. A test proves it statically and at runtime (
tests/test_nur_lesen.py). OnlyBODY.PEEKis used, so reading never sets\Seen. SMTP is not exposed.One token per consumer, with scopes:
proton.read,proton.attachments,proton.ablage. Checked inside every tool, not just at the transport.Mail content is untrusted input. Bodies are wrapped in random-nonce markers, invisible Unicode is stripped, every response carries
content_trust=untrusted_email. Size, pixel and time limits against hostile attachments; a parser that survives broken and malicious mails.No published port. The MCP joins the agent's Docker network only.
Audit log per tool call — who, what, when, how much — never mail content.
Authenticity per mail from Proton's own SPF/DKIM/DMARC results, evaluated worst-case so a forged „pass“ header cannot mask a „fail“.
Search that works with umlauts and multiple words — the Bridge compares IMAP
SEARCHagainst encoded headers, so the server matches decoded text itself (see below, German).
Tools: list_mailboxes, search_emails, get_thread, get_email, get_attachment_text
(PDF text or OCR), get_attachment, get_attachment_image (render for vision models) and
anhang_ablegen (store an attachment in a shared folder without passing the bytes through the
model; strict file-name sanitising, extension allow-list, atomic writes, never outside the drop
directory).
Quick start: uv sync --group dev, copy .env.example to .env, then
uv run proton-check and uv run python -m proton_mail.mcp_server. Docker deployment with a
headless Bridge built from Proton's signed Debian package: docker/DEPLOY.md.
The code comments and the detailed documentation below are in German.
License: MIT, see LICENSE. Note: the dependency
PyMuPDF is licensed under AGPL-3.0 (or a commercial
license from Artifex). The MIT license covers this project's own code; if you distribute or run
it as a network service together with PyMuPDF, the AGPL-3.0 terms of PyMuPDF apply to that
combination. Proton Mail Bridge itself is GPL-3.0 and is downloaded at build time, not included.
Deutsch
Inoffiziell. Dieses Projekt steht in keiner Verbindung zur Proton AG und wird von ihr weder unterstützt noch gebilligt. „Proton“ und „Proton Mail“ sind Marken der Proton AG.
Eigenbau-Connector für lesenden Zugriff auf Proton Mail über die offizielle Proton Mail Bridge (IMAP). Zwei Frontends auf einem gemeinsamen Lese-Kern:
MCP-Server — sieben Lese-Tools und
anhang_ablegen(schreibt einen Anhang in einen Austauschordner, nie ins Postfach). Gedacht als Dienst ohne LAN-Port im Docker-Netz eines Agenten. Eine Anbindung von claude.ai über OAuth (Variante B) ist vorbereitet.Bulk-Läufe —
export.py,tax_export.py,scanner_pdfs.pyladen Mails/Anhänge strukturiert auf die Platte (z. B. für Steuer oder ein Dokumentenarchiv).
Betrieb und Aufbau mit Docker: docker/DEPLOY.md.
Related MCP server: proton-bridge-mcp
Designprinzipien
Kein Schreibpfad ins Postfach. Der Lese-Kern (
imap_client.py) kennt keine Methode zum Senden, Löschen, Verschieben oder Taggen. Auch im Netz nicht: die Bridge exponiert nur IMAP (143), kein SMTP.Ein Token je Konsument, mit Scopes.
proton.read(Listen, Suchen, Mailtext, Anhangs-Text),proton.attachments(rohe Anhänge, Bild-Rendering) undproton.ablage(anhang_ablegen, nur ausdrücklich je Token — nie für das Alt-Token oder OAuth-Clients). Die Prüfung sitzt im Tool, nicht nur im Client.Grenzen gegen fremde Eingaben. Mail-Cap 50 MB, Anhang-Cap 10 MB, Render-Cap 20 MP, OCR-Timeout, Textkürzung, HTML wird zu Text reduziert.
Kein Port ins LAN. Der MCP tritt nur dem Docker-Netz des Agenten bei.
Tools
Tool | Scope | Liefert |
| read | Ordner und Labels |
| read | ganze Unterhaltung (Message-ID/References/In-Reply-To in „All Mail“), älteste zuerst |
| read |
|
| read | Text (bei Bedarf HTML→Text), Anhang-Metadaten; |
| read | PDF-Text oder OCR ( |
| attachments | Anhang als base64 |
| attachments | erste PDF-Seite / Bild als PNG (Vision) |
| ablage | legt einen Anhang im Austauschordner ab; liefert nur Pfad, Größe, MIME, sha256 |
anhang_ablegen
Damit ein Agent einen Anhang „in den Ordner legen" kann, ohne dass die Rohdaten durch das
Modell laufen: Der Server holt die Bytes selbst und schreibt sie nach
$ATTACHMENT_DROP_DIR (z. B. eine Netzfreigabe, die der Agent ebenfalls eingehängt hat).
Adressierung wie
get_attachment:uid,mailbox,indexODERfilename.Ziel:
Anhänge/<JJJJ-MM-TT> <Absender> (<Domain>) – <Betreff>/<Datei>; das Datum ist der Eingang beim Server (IMAPINTERNALDATE, Europe/Berlin), nicht der fälschbare Date-Header (der nur als Rückfall); die Domain stammt aus der Absenderadresse. Mitunterordner(max. 3 Ebenen, z. B.Steuer 2026) stattdessenAnhänge/<unterordner>/<Datei>.Sanitisierung jedes Bestandteils: Unicode NFC, Steuer-, Format- und alle Default_Ignorable-Zeichen raus (RTL-Override, Nullbreite, Hangul-Füllzeichen, CGJ, Variationsselektoren), Punkt-Doppelgänger (U+2024, U+FE52, U+FF0E) →
_,< > : " / \ | ? *→_, keine Punkte/Leerzeichen am Ende, reservierte Namen (CON,NUL,COM¹,CONIN$… auch mit Endung) mit_davor.Längen: je Bestandteil höchstens 200 UTF-8-Bytes (an Zeichengrenze, Endung bleibt; zusätzlich Datei 120, Ordner 100 Zeichen); der ganze Pfad ab der Freigabe (
Anhänge/…) höchstens 240 UTF-16-Einheiten inkl. Reserve für(999)— erst wird der Betreff gekürzt, dann der Dateistamm; reicht das nicht (langerunterordner), kommt ein Fehler.Endungen nach Positivliste: unverändert bleiben nur
pdf jpg jpeg png gif webp heic heif tif tiff bmp txt csv md xml json docx xlsx pptx odt ods odp rtf zip eml ics vcf mp3 m4a mp4 mov. Alles andere — auch ohne Endung,.docm,.html,.svg,desktop.ini— bekommt.blockiertangehängt; maßgeblich ist die letzte Endung (rechnung.pdf.exe→ blockiert).Agenten-Steuerdateien (
CLAUDE.md,CLAUDE.local.md,AGENTS.md,AGENT.md,.mcp.json,GEMINI.md,QWEN.md,HERMES.md,SOUL.md,CONVENTIONS.md,CRUSH.md, groß/klein egal) →.txtangehängt — geprüft vor der Positivliste. Führender Punkt →_. Jede Umbenennung steht inhinweise.Kein Überschreiben (
(2),(3)…); liegt derselbe Inhalt (sha256) schon im Zielordner, kommt dessen Pfad mit Hinweis „bereits vorhanden" zurück, keine zweite Kopie. Atomar (Temp-Datei.~ablage-*.tmpim Zielordner, dannrename); verwaiste Temp-Dateien älter als 1 h räumt der Server vor der ersten Ablage je Prozess weg. Nie außerhalb des Ablageverzeichnisses (realpath-Prüfung, auch gegen Symlinks).Grenze
ATTACHMENT_DROP_MAX_MB(Standard 50); die Mail-Grenze wird für dieses Werkzeug passend angehoben (base64 +33 %).Fehlt die Ablage (Freigabe nicht eingehängt, nicht beschreibbar, Variable leer), kommt eine klare Fehlermeldung — vor jeder Bridge-Abfrage.
Rückgabe:
pfad,pfad_konsument,groesse,mime,sha256,dateiname_original(höchstens 200 Zeichen, unsichtbare/Steuerzeichen alsusw. sichtbar),hinweise. Nie der Inhalt. Das Log enthält nur UID, Größe und sha256-Präfix.
Warum die Suche nicht einfach die Bridge fragt
Die Proton Bridge vergleicht IMAP-SEARCH-Begriffe mit dem kodierten Header/Text
(RFC 2047, Quoted-Printable, Base64). Gemessen: SUBJECT "Zustellung fehlgeschlagen" → 0,
"Bestätigung" → 0, TEXT "Grüße" → 0, aber "Ihre_Bestellung" → 1.
suche.py prüft deshalb die neuesten 25.000 Mails (mit Textsuche 3.000) selbst gegen den
dekodierten Betreff/Absender/Empfänger und den Mailtext (erste 128 KB) und fragt die Bridge
nur für Ältere grob nach dem längsten ASCII-Wort — teuer (auf rund 100.000 Mails 18–42 s), daher
nur, wenn das Fenster nicht reicht. Typisch 0,3–2 s, Worst Case (seltenes Wort in „All Mail")
rund 22 s. reader.search() bleibt die rohe Bridge-Suche für die Bulk-Skripte.
Lokale Entwicklung
uv sync --group dev
cp .env.example .env # Bridge-Zugangsdaten + MCP_STATIC_TOKENS eintragen
uv run proton-check # IMAP gegen die lokale Bridge (127.0.0.1:1143)
uv run python -m proton_mail.mcp_server
MCP_SMOKE_TOKEN=… uv run python scripts/smoke_mcp.py
uv run ruff check src scripts tests && uv run pytest -qDer Server startet auch ohne erreichbare Bridge — die IMAP-Verbindung wird erst beim ersten Tool-Aufruf geöffnet.
Konfiguration (Umgebung)
Variable | Zweck |
| Bridge-Mailbox-Zugangsdaten (nicht das Proton-Passwort) |
| Bridge-IMAP; im Container |
|
|
| Altform, ein Token mit |
|
|
| erlaubte Host-Header (DNS-Rebinding-Schutz) |
| Größen-Caps (10 / 50) |
| Ablageverzeichnis für |
| Grenze für |
| Pfad, unter dem der Konsument den Eltern-Ordner der Ablage sieht |
| Abruf-Protokoll (JSON-Zeilen), leer = aus |
|
|
| nur Variante B |
| Bulk-Läufe |
Projektstruktur
src/proton_mail/
config.py # Env-Konfiguration, Token-Parsing, Scopes
imap_client.py # Read-only IMAP-Kern (Proton Bridge), Größenprüfung
message.py # MIME-/Anhang-Parsing, HTML→Text
ocr.py # PDF-Text, OCR, Render — mit Pixel-/Zeit-Grenzen
oauth.py # StaticTokenVerifier (A) + MinimalOAuthProvider (B)
mcp_server.py # die Tools (async, Threads), /healthz, /readyz
untrusted.py # Mailinhalt als fremd kennzeichnen (Rahmen, unsichtbare Zeichen raus)
audit.py # Abruf-Protokoll: eine JSON-Zeile je Tool-Aufruf, nie Mailinhalt
suche.py # Suche trotz Bridge: grob beim Server, genau gegen dekodierten Text
echtheit.py # SPF/DKIM/DMARC + Proton-Spamwert je Mail, fälschungsfest ausgewertet
ablage.py # anhang_ablegen: Namensregeln, Verbote, atomares Schreiben
export.py, tax_export.py, scanner_pdfs.py # Bulk-Läufe
docker/
Dockerfile, bridge.Dockerfile, bridge-entrypoint.sh, gpgparams
compose.bridge.yaml # Bridge-Stack — selten ändern (Recreate behält den Login)
compose.mcp.yaml # MCP-Stack — beliebig neu baubar
DEPLOY.md, .env.example
scripts/
smoke_mcp.py # End-to-End-Test
check_attachments.py # Anhangs-Text über viele Mails prüfen
tests/ # pytest: Tokens/Scopes, Grenzen, OAuth, Ablage, Suche, nie schreibendSicherheit
Secrets nur in
.env-Dateien, nie im Repo.Bridge-TLS ist selbstsigniert →
IMAP_TLS_VERIFY=falsenur im internen Docker-Netz.Kein Logging von Mailinhalten; Access-Log des Servers ist aus.
Mailinhalt ist fremder Text: Text, HTML und Anhangstext stehen in einem Rahmen mit Zufallsmarke (
<<<MAILINHALT …>>>), unsichtbare Unicode-Zeichen (Zero-Width, Bidi, Tag-Zeichen) werden entfernt, Kurzfelder geglättet, jede Antwort trägtcontent_trust=untrusted_email; dazu Server-Instructions und Tool-Annotationen. Das ist ein Hinweis ans Modell, kein Schutz — der Schutz bleibt der fehlende Schreibpfad ins Postfach.max_charsist auf 100.000 gedeckelt, auch bei 0 oder negativen Werten.Abruf-Protokoll je Tool-Aufruf (
MCP_AUDIT_LOG): wer, was, wann, wie groß — ohne Mailinhalt.Echtheit je Mail (
echtheit): nur Protons eigene Prüfzeilen (mail.protonmail.ch), je Prüfung das schlechteste Ergebnis — eine vom Absender eingeschmuggelte „pass"-Zeile überdeckt kein „fail". Urteilbestanden | teilweise | nicht_bestanden | ungeprueft | intern; importierte Altpost (iCloud/Gmail) istungeprueft.Beweistest „nie schreibend" (
tests/test_nur_lesen.py): statisch nur erlaubte IMAP-Methoden, jedesselect_foldermitreadonly=True, nurBODY.PEEK; zur Laufzeit alle Werkzeuge gegen einen IMAP-Nachbau, der jeden anderen Aufruf meldet.CI (
.github/workflows/tests.yml): ruff, pytest, pip-audit bei jedem Push; Actions auf Commit-SHA gepinnt. Dependabot wöchentlich, ohne Major-Sprünge für mcp/imapclient.Abhängigkeiten gepinnt (
uv.lock), Basis-Images auf Digest, Container read-only ohne Capabilities.
Lizenz
MIT, siehe LICENSE. Hinweis: Die Abhängigkeit
PyMuPDF steht unter AGPL-3.0 (oder einer
kommerziellen Lizenz von Artifex). Die MIT-Lizenz gilt für den Code dieses Projekts; wer ihn
zusammen mit PyMuPDF weitergibt oder als Netzwerkdienst betreibt, unterliegt für diese
Kombination den AGPL-3.0-Bedingungen von PyMuPDF. Die Proton Mail Bridge selbst steht unter
GPL-3.0 und wird beim Bau heruntergeladen, nicht mitgeliefert.
Related MCP Connectors
Your mailboxes in ChatGPT and Claude: Gmail, iCloud, Fastmail, any IMAP. Passwords stay yours.
Email inboxes and calendars for AI agents: send, receive, search, draft and schedule.
Email inboxes and calendars for AI agents: send, receive, search, draft and schedule.
- Lettio MCPOAutheu.lettio
Private, EU-hosted email for AI agents over JMAP: read, search, reply, organize, send.
Related MCP Servers
- AlicenseAqualityAmaintenanceEnables AI agents to send, read, search, and organize emails via ProtonMail using Proton Bridge. Supports MCP-compatible clients like Claude and Cursor.1847 npm4MIT
- AlicenseAqualityBmaintenanceEnables AI assistants to read and search Proton Mail inbox through Proton Mail Bridge, providing tools to list mailboxes, list messages, search messages, and fetch full message bodies. Read-only, with secure certificate pinning.417 npm1MIT
- AlicenseNot gradedqualityCmaintenanceProvides read-only access to Proton Mail via MCP, enabling AI agents to list accounts/folders, search messages, and read emails using Proton Mail Bridge's local IMAP server.MIT
- FlicenseNot gradedqualityCmaintenanceEnables AI assistants to interact with a Proton Mail mailbox through Proton Bridge, supporting listing, searching, reading, sending, and organizing emails.-