Add create_draft tool to Mail server

Creates email drafts via IMAP APPEND to the Drafts folder.
Supports Stefan (1blu, Drafts folder) and Kati (Gmail, Entwürfe).
Draft can be reviewed and sent from Roundcube or phone.

IMAP credentials externalized to config.json.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Stefan Lohmaier
2026-06-12 08:16:53 +02:00
parent 5190e8c849
commit 1f98695821
+57 -1
View File
@@ -3,8 +3,11 @@
import os
import sys
import contextlib
import imaplib
import mailbox
from email.header import decode_header
from email.mime.text import MIMEText
from email.utils import formatdate
from pathlib import Path
from typing import Annotated
@@ -17,7 +20,25 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
from common import get_current_user, OAUTH_ROUTES, BearerAuthMiddleware
from common import load_config as _lc
MAIL_ROOTS = _lc()["mail_roots"]
_cfg = _lc()
MAIL_ROOTS = _cfg["mail_roots"]
IMAP_ACCOUNTS = {
"stefan": {
"host": "imap.1blu.de",
"user": "d370128_0-slohmaier",
"password": _cfg["imap_passwords"]["stefan"],
"drafts_folder": "Drafts",
"from_addr": "stefan@slohmaier.de",
},
"kati": {
"host": "imap.gmail.com",
"user": "akpolke@gmail.com",
"password": _cfg["imap_passwords"]["kati"],
"drafts_folder": "[Google Mail]/Entw&APw-rfe",
"from_addr": "akpolke@gmail.com",
},
}
mcp = FastMCP("Mail", stateless_http=True,
transport_security={"enable_dns_rebinding_protection": False})
@@ -171,6 +192,41 @@ def read_mail(
)
@mcp.tool()
def create_draft(
to: Annotated[str, Field(description="Recipient email address, e.g. 'max@example.com'")],
subject: Annotated[str, Field(description="Email subject line")],
body: Annotated[str, Field(description="Email body text (plain text)")],
cc: Annotated[str, Field(description="CC recipients, comma-separated")] = "",
account: Annotated[str, Field(description="Which account to create the draft in. Leave empty for default account.")] = "",
) -> str:
"""Create an email draft in the Drafts folder. The draft can then be reviewed and sent from Roundcube or phone. Does NOT send the email."""
user = get_current_user()
if not user: return "Error: not authenticated"
acct = IMAP_ACCOUNTS.get(user)
if not acct: return f"Kein IMAP-Account fuer {user} konfiguriert"
msg = MIMEText(body, "plain", "utf-8")
msg["From"] = acct["from_addr"]
msg["To"] = to
if cc:
msg["Cc"] = cc
msg["Subject"] = subject
msg["Date"] = formatdate(localtime=True)
msg["X-Mailer"] = "MCP Mail Server"
try:
imap = imaplib.IMAP4_SSL(acct["host"])
imap.login(acct["user"], acct["password"])
status, _ = imap.append(acct["drafts_folder"], "\\Draft", None, msg.as_bytes())
imap.logout()
if status == "OK":
return f"Entwurf erstellt: An {to}, Betreff \"{subject}\". Oeffne Roundcube oder die Mail-App um ihn zu senden."
return f"Fehler beim Erstellen des Entwurfs: {status}"
except Exception as e:
return f"IMAP-Fehler: {e}"
def create_app():
from contextlib import asynccontextmanager
mcp_app = mcp.streamable_http_app()