odysseus-dev/odysseus · error · ValueError

No SMTP-capable email account configured

Error message

No SMTP-capable email account configured

What it means

Terminal error from _resolve_send_config: no explicit account was given (or the default config is not SMTP-ready), and the loop over every account row in _list_accounts_raw() found none whose config passes _smtp_ready(). There is literally no account able to send mail.

Source

Thrown at mcp_servers/email_server.py:1327

    return {"error": f"Email not found in any configured account. Checked: {'; '.join(errors)}"}


def _smtp_ready(cfg: dict) -> bool:
    return bool(cfg.get("smtp_host") and cfg.get("smtp_user") and cfg.get("smtp_password"))


def _resolve_send_config(account=None):
    cfg = _load_config(account)
    if _smtp_ready(cfg):
        return account, cfg
    if account:
        raise ValueError(f"Email account {cfg.get('account_name') or account} has no SMTP configured")
    for row in _list_accounts_raw():
        selector = row.get("id") or row.get("name") or row.get("imap_user")
        trial = _load_config(selector)
        if _smtp_ready(trial):
            return selector, trial
    raise ValueError("No SMTP-capable email account configured")


def _smtp_connect(account=None, cfg=None):
    """Connect to SMTP server, returns logged-in connection."""
    cfg = cfg or _load_config(account)
    if not _smtp_ready(cfg):
        raise ValueError(f"Email account {cfg.get('account_name') or account or 'default'} has no SMTP configured")
    port = int(cfg.get("smtp_port") or 465)
    security = str(cfg.get("smtp_security") or "").strip().lower()
    if security not in {"ssl", "starttls", "none"}:
        security = "starttls" if port == 587 else "ssl"
    if security == "starttls":
        conn = smtplib.SMTP(
            cfg["smtp_host"],
            port,
            timeout=EMAIL_SOCKET_TIMEOUT,
        )
        try:

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Configure SMTP (host/port/user/password/security) for at least one account
  2. Confirm the MCP server process can read the SMTP values (DB row or env) — restart it after changes
  3. If the accounts DB is empty, add an account first

Example fix

# before: no account has SMTP
send_email(to='x@y.com', subject='hi', body='hi')
# after
account = {'name':'main','imap_host':'...','smtp_host':'smtp.example.com','smtp_port':465,'smtp_user':'me@example.com','smtp_password':'<app-password>','smtp_security':'ssl'}
send_email(account='main', to='x@y.com', subject='hi', body='hi')
Defensive patterns

Strategy: validation

Validate before calling

if not any(_smtp_ready(_load_config(r.get('id') or r.get('name'))) for r in _list_accounts_raw()):
    raise SystemExit('No SMTP-capable account configured — add one before sending')

Type guard

def any_smtp_capable() -> bool:
    return any(_smtp_ready(_load_config(r.get('id') or r.get('name') or r.get('imap_user'))) for r in _list_accounts_raw())

Try / catch

try:
    acct, cfg = _resolve_send_config()
except ValueError as e:
    if 'No SMTP-capable' in str(e):
        fall_back_to_queue_or_log()
    raise

Prevention

When it happens

Trigger: Calling send_email() with no account argument on a system where zero accounts have smtp_host+smtp_user+smtp_password set (or the accounts DB is empty).

Common situations: Fresh install with only IMAP credentials configured; SMTP password field cleared after a credential rotation; smtp_* environment variables not present in the MCP server process env.

Related errors


AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14). Data as JSON: /api/errors/97769144e5a95442. Report an issue: GitHub.