odysseus-dev/odysseus · error · ValueError
Email account {cfg.get('account_name') or account} has no SM
Error message
Email account {cfg.get('account_name') or account} has no SMTP configured What it means
Raised by _resolve_send_config when the caller explicitly names an account but _smtp_ready(cfg) is false — the loaded config is missing smtp_host, smtp_user, or smtp_password. Sending requires SMTP credentials even though IMAP reading may already work.
Source
Thrown at mcp_servers/email_server.py:1321
return {
"error": (
f"UID {uid or message_id} exists in multiple accounts: {accounts}. "
"Call read_email again with the account name/email."
)
}
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":View on GitHub (pinned to f9235ebbf1)
Solutions
- Set smtp_host, smtp_port, smtp_user, smtp_password (and smtp_security) on that account's row/config
- Verify the SMTP password is stored encrypted via src.secret_storage and decrypts correctly
- If you meant to send from any account, omit the account argument so the fallback scan finds an SMTP-capable one
Example fix
# before send_email(account='imap-only-acct', ...) # after — configure SMTP on the account, or drop the explicit selector send_email(..., account='main-account-with-smtp')
Defensive patterns
Strategy: type-guard
Validate before calling
if not _smtp_ready(_load_config(account)):
raise ValueError(f'{account} cannot send; configure SMTP or drop the selector') Type guard
def can_send(account: str | None) -> bool:
return _smtp_ready(_load_config(account)) Try / catch
try:
acct, cfg = _resolve_send_config(account)
except ValueError as e:
if 'no SMTP configured' in str(e):
notify_admin_to_configure_smtp(e)
raise Prevention
- Validate SMTP readiness in account-setup wizards before saving
- Keep IMAP-only accounts out of send call sites
- Store SMTP creds via the same encrypted path as IMAP
When it happens
Trigger: Calling a send/draft tool with account=<selector> where that account's row (and env/config fallbacks) lacks any SMTP field — e.g. an account configured for IMAP-only reading.
Common situations: Read-only mail accounts (import/scan setups) reused for sending; SMTP password stored encrypted but the smtp_host column empty; provider requires app-specific SMTP password that was never set.
Related errors
- No SMTP-capable email account configured
- Email account {cfg.get('account_name') or account or 'defaul
- Email account {cfg.get('account_name') or account_id} has no
- No SMTP-capable email account configured
- Unsubscribe failed
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/bd81e30857958e6f.
Report an issue: GitHub.