Setting up secure email automation with Proton Bridge and MCP

Proton Bridge Email Automation using Docker MCP and Claude

I want to create a secure email automation system that doesn’t compromise on privacy. Most email automation tools require storing credentials in third-party services and granting broad access permissions.

Requirements

  • Docker Desktop with MCP Toolkit enabled
  • Docker MCP CLI plugin (docker mcp command)
  • Proton Bridge installed and running locally
  • Valid ProtonMail account with Bridge credentials
  • Claude Desktop installed

Outcomes

  • Complete privacy with local processing
  • End-to-end encryption maintained
  • AI-powered email management through Claude
  • No external data sharing

Step #1: Create the MCP Server Files

Set up your project directory and create the necessary files:

mkdir proton-email-mcp-server
cd proton-email-mcp-server

Create the Dockerfile:

# Use Python slim image
FROM python:3.11-slim

# Set working directory
WORKDIR /app

# Set Python unbuffered mode
ENV PYTHONUNBUFFERED=1

# Copy requirements first for better caching
COPY requirements.txt .

# Install dependencies
RUN pip install --no-cache-dir -r requirements.txt

# Copy the server code
COPY proton_email_server.py .

# Create non-root user
RUN useradd -m -u 1000 mcpuser && \
    chown -R mcpuser:mcpuser /app

# Switch to non-root user
USER mcpuser

# Run the server
CMD ["python", "proton_email_server.py"]

Create requirements.txt:

mcp[cli]>=1.2.0
httpx
python-dotenv
secure-smtplib

Step #2: Configure the Main Server Code

Create proton_email_server.py with the complete MCP server implementation:

#!/usr/bin/env python3
"""
Simple Proton Bridge Email MCP Server - Read and send emails via Proton Bridge
"""
import os
import sys
import logging
import imaplib
import smtplib
import email
from email.header import decode_header
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from datetime import datetime, timezone
from mcp.server.fastmcp import FastMCP

# Configure logging to stderr
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    stream=sys.stderr
)
logger = logging.getLogger("proton-email-server")

# Initialize MCP server
mcp = FastMCP("proton-email")

# Configuration
PROTON_USERNAME = os.environ.get("PROTON_USERNAME", "")
PROTON_PASSWORD = os.environ.get("PROTON_PASSWORD", "")
PROTON_BRIDGE_HOST = os.environ.get("PROTON_BRIDGE_HOST", "127.0.0.1")
PROTON_BRIDGE_IMAP_PORT = int(os.environ.get("PROTON_BRIDGE_IMAP_PORT", "1143"))
PROTON_BRIDGE_SMTP_PORT = int(os.environ.get("PROTON_BRIDGE_SMTP_PORT", "1025"))

@mcp.tool()
async def read_recent_emails(count: str = "10", folder: str = "INBOX") -> str:
    """Read recent emails from specified folder with optional count limit."""
    logger.info(f"Reading {count} emails from {folder}")

    if not PROTON_USERNAME or not PROTON_PASSWORD:
        return "❌ Error: Proton credentials not configured. Set PROTON_USERNAME and PROTON_PASSWORD."

    try:
        limit = int(count) if count.strip() else 10
        if limit > 50:
            limit = 50

        mail = imaplib.IMAP4(PROTON_BRIDGE_HOST, PROTON_BRIDGE_IMAP_PORT)
        mail.login(PROTON_USERNAME, PROTON_PASSWORD)
        mail.select(folder)

        status, messages = mail.search(None, "ALL")
        mail_ids = messages[0].split()

        if not mail_ids:
            mail.logout()
            return f"📭 No emails found in {folder}."

        # Process emails and return formatted results
        # [Additional implementation details...]

        mail.logout()
        return result

    except Exception as e:
        logger.error(f"Error reading emails: {e}")
        return f"❌ Error reading emails: {str(e)}"

@mcp.tool()
async def send_email(to_email: str = "", subject: str = "", body: str = "", cc: str = "", bcc: str = "") -> str:
    """Send an email via Proton Bridge SMTP."""
    logger.info(f"Sending email to {to_email}")

    if not to_email.strip() or not subject.strip() or not body.strip():
        return "❌ Error: to_email, subject, and body are required"

    try:
        # Create and send email via SMTP
        # [Implementation details...]

        return f"✅ Email sent successfully to {to_email}"

    except Exception as e:
        logger.error(f"Error sending email: {e}")
        return f"❌ Error sending email: {str(e)}"

if __name__ == "__main__":
    logger.info("Starting Proton Bridge Email MCP server...")
    mcp.run(transport='stdio')

Step #3: Build and Configure the Docker Container

Build the Docker image:

docker build -t proton-email-mcp-server .

Set up secure credentials using Docker secrets:

docker mcp secret set PROTON_USERNAME="[email protected]"
docker mcp secret set PROTON_PASSWORD="your-bridge-password"
docker mcp secret set PROTON_BRIDGE_HOST="host.docker.internal"
docker mcp secret set PROTON_BRIDGE_IMAP_PORT="1143"
docker mcp secret set PROTON_BRIDGE_SMTP_PORT="1025"

Step #4: Create the Custom Catalog Configuration

Create the custom catalog file:

mkdir %USERPROFILE%\.docker\mcp\catalogs
notepad %USERPROFILE%\.docker\mcp\catalogs\custom.yaml

Add the catalog configuration:

version: 2
name: custom
displayName: Custom MCP Servers
registry:
  proton-email:
    description: "Read and send emails via Proton Bridge with secure IMAP/SMTP access"
    title: "Proton Bridge Email"
    type: server
    dateAdded: "2025-09-14T00:00:00Z"
    image: proton-email-mcp-server:latest
    tools:
      - name: read_recent_emails
      - name: search_emails
      - name: send_email
      - name: list_folders
      - name: get_email_stats
    secrets:
      - name: PROTON_USERNAME
        env: PROTON_USERNAME
        example: "[email protected]"
      - name: PROTON_PASSWORD
        env: PROTON_PASSWORD
        example: "your-bridge-password"
    metadata:
      category: productivity
      tags:
        - email
        - protonmail
        - encryption
        - privacy

Step #5: Configure Claude Desktop Integration

Edit your Claude Desktop config file at %APPDATA%\Claude\claude_desktop_config.json:

{
  "mcpServers": {
    "mcp-toolkit-gateway": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "-v", "/var/run/docker.sock:/var/run/docker.sock",
        "-v", "C:\\Users\\your_username\\.docker\\mcp:/mcp",
        "docker/mcp-gateway",
        "--catalog=/mcp/catalogs/docker-mcp.yaml",
        "--catalog=/mcp/catalogs/custom.yaml",
        "--config=/mcp/config.yaml",
        "--registry=/mcp/registry.yaml",
        "--tools-config=/mcp/tools.yaml",
        "--transport=stdio"
      ]
    }
  }
}

Step #6: Test Your Setup

After restarting Claude Desktop, you can test the integration:

# Test Bridge connectivity
telnet 127.0.0.1 1143

You should see: * OK [CAPABILITY...] Proton Mail Bridge...

Ask Claude to:

  • “Show me my 5 most recent emails”
  • “Search for emails about ‘meeting’ in my inbox”
  • “Send an email to [email protected] about tomorrow’s presentation”

By