""" tools/email_tool.py — IMAP email reading + SMTP sending. Read operations: list_emails, read_email — no confirmation required. Send operation: send_email — whitelisted recipients only, requires confirmation. Prompt injection guard: all email body text is sanitised before returning to agent. Max body length: 10,000 characters (truncated with notice). """ from __future__ import annotations import email as email_lib import smtplib import ssl from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.utils import formatdate, make_msgid, parseaddr import imapclient from bs4 import BeautifulSoup from ..database import credential_store from ..security import SecurityError, assert_email_rate_limit, assert_recipient_allowed, sanitize_external_content from ..security_screening import get_content_limit, is_option_enabled from .base import BaseTool, ToolResult MAX_BODY_CHARS = 10_000 # legacy fallback when truncation option disabled _DEFAULT_MAX_EMAIL_CHARS = 6_000 # default when truncation option enabled _DEFAULT_MAX_SUBJECT_CHARS = 200 # default subject limit when truncation option enabled MAX_LIST_EMAILS = 50 class EmailTool(BaseTool): name = "email" description = ( "Read and send emails via IMAP/SMTP (Mailcow). " "Operations: list_emails (list inbox), read_email (read full message), " "send_email (send to one or more whitelisted recipients — requires confirmation), " "list_whitelist (return all approved recipient addresses). " "Email bodies are sanitised before being returned." ) input_schema = { "type": "object", "properties": { "operation": { "type": "string", "enum": ["list_emails", "read_email", "send_email", "list_whitelist"], "description": "The email operation to perform. list_whitelist returns all approved recipient addresses.", }, "folder": { "type": "string", "description": "IMAP folder (default: INBOX)", }, "limit": { "type": "integer", "description": f"Max emails to list (default 20, max {MAX_LIST_EMAILS})", }, "unread_only": { "type": "boolean", "description": "Only list unread emails (default false)", }, "email_id": { "type": "string", "description": "Email UID for read_email", }, "to": { "anyOf": [ {"type": "string"}, {"type": "array", "items": {"type": "string"}}, ], "description": "Recipient address or list of addresses for send_email (all must be whitelisted)", }, "subject": { "type": "string", "description": "Email subject for send_email", }, "body": { "type": "string", "description": "Email body text (plain text) for send_email", }, "html_body": { "type": "string", "description": "Full HTML email body for send_email. If provided, used as the HTML part instead of the plain-text fallback wrapper. Include complete ... with inline