Skip to main content
Use the Mail interface to serve Agents via standard SMTP/IMAP email. It mounts API routes on a FastAPI app and enables automated email processing, replies, and full inbox management. Works with any mail provider (Gmail, Outlook, Yahoo, Zoho, self-hosted, etc.).

Installation

Install the Mail interface dependencies:
uv pip install "upsonic[mail-interface]"

Setup

Configuration via constructor parameters or environment variables:
Env VariableDescription
MAIL_SMTP_HOSTSMTP server hostname
MAIL_SMTP_PORTSMTP server port (default: 587)
MAIL_IMAP_HOSTIMAP server hostname
MAIL_IMAP_PORTIMAP server port (default: 993)
MAIL_USERNAMEEmail account username
MAIL_PASSWORDEmail account password (or app password)
MAIL_USE_SSLUse SSL for SMTP instead of STARTTLS (default: false)
MAIL_API_SECRETSecret token for API endpoint protection (optional)
The interface uses a pull-based model - you trigger email checks via the /mail/check endpoint (or use heartbeat auto-poll), and the agent processes unread emails.

Common Provider Settings

ProviderSMTP HostSMTP PortIMAP HostIMAP Port
Gmailsmtp.gmail.com587imap.gmail.com993
Outlooksmtp.office365.com587outlook.office365.com993
Yahoosmtp.mail.yahoo.com587imap.mail.yahoo.com993
Zohosmtp.zoho.com587imap.zoho.com993
Most providers require an App Password (not your regular password) when using SMTP/IMAP. For Gmail, enable 2-Step Verification first, then generate an App Password at myaccount.google.com/apppasswords. For Gmail, you also need to enable IMAP in Settings > Forwarding and POP/IMAP.

Operating Modes

  • TASK (default) — Each email is processed as an independent task; no conversation history. The agent decides to reply or ignore. Best for classification, auto-responders, one-off processing.
  • CHAT — Emails from the same sender share a conversation session. The agent remembers context from previous emails. Best for support threads and ongoing conversations.

Reset Command (CHAT mode only)

In CHAT mode, senders can clear their conversation by sending an email with the reset command in the body (e.g. /reset). Configure it with reset_command; set to None to disable. If the agent has a workspace configured, the reset command will also trigger a dynamic greeting message based on the workspace configuration. See Workspace for details.

Heartbeat (Auto-Poll)

When used with an AutonomousAgent that has heartbeat=True, the interface automatically polls the IMAP mailbox for new emails on a configurable interval. No need to manually trigger /mail/check.
from upsonic import AutonomousAgent
from upsonic.interfaces import InterfaceManager, MailInterface

agent = AutonomousAgent(
    model="openai/gpt-4o",
    name="EmailBot",
    heartbeat=True,
    heartbeat_period=5,  # Check every 5 minutes
    heartbeat_message="Check for new emails and process them.",
)

mail = MailInterface(
    agent=agent,
    smtp_host="smtp.gmail.com",
    smtp_port=587,
    imap_host="imap.gmail.com",
    imap_port=993,
    username="bot@gmail.com",
    password="your-app-password",
    mode="task",
)

manager = InterfaceManager(interfaces=[mail])

if __name__ == "__main__":
    manager.serve(host="0.0.0.0", port=8000)

Access Control (Whitelist)

Pass allowed_emails (list of email addresses). Only emails from those senders are processed; others are silently skipped and marked as read. Omit allowed_emails (or set None) to allow all senders.

Attachments

The Mail interface fully supports attachments in both directions:
  • Incoming: Attachments on received emails are downloaded to temporary files and passed to the agent via Task(context=...). Temp files are cleaned up automatically after processing.
  • Outgoing: The agent can send emails with file attachments using the send_email_with_attachments and send_reply_with_attachments tools.

Multiple Recipients

The send_email tool supports sending to multiple recipients with CC and BCC:
mail_tools.send_email(
    to=["alice@example.com", "bob@example.com"],
    subject="Team Update",
    body="Hello team!",
    cc="manager@example.com",
    bcc=["audit@example.com"],
)

Event Deduplication

The interface automatically prevents processing the same email twice within a 5-minute window. This protects against rapid consecutive calls to /mail/check.

Example Usage

Create an agent, expose it with the MailInterface, and serve via InterfaceManager. Example with TASK mode, API secret, and whitelist:
import os
from upsonic import Agent
from upsonic.interfaces import InterfaceManager, MailInterface, InterfaceMode

agent = Agent(
    model="openai/gpt-4o",
    name="EmailAssistant",
)

mail = MailInterface(
    agent=agent,
    smtp_host="smtp.gmail.com",
    smtp_port=587,
    imap_host="imap.gmail.com",
    imap_port=993,
    username="mybot@gmail.com",
    password=os.getenv("MAIL_PASSWORD"),
    api_secret=os.getenv("MAIL_API_SECRET"),
    mode=InterfaceMode.TASK,
    reset_command="/reset",
    allowed_emails=["trusted@example.com", "support@mycompany.com"],
)

manager = InterfaceManager(interfaces=[mail])

if __name__ == "__main__":
    manager.serve(host="0.0.0.0", port=8000, reload=False)

CHAT Mode Example

mail = MailInterface(
    agent=agent,
    smtp_host="smtp.gmail.com",
    smtp_port=587,
    imap_host="imap.gmail.com",
    imap_port=993,
    username="mybot@gmail.com",
    password=os.getenv("MAIL_PASSWORD"),
    mode=InterfaceMode.CHAT,
    reset_command="/reset",
)
In CHAT mode, each sender gets their own conversation session. The agent remembers previous exchanges. Send /reset in an email body to start fresh.

Core Components

  • MailInterface (interface): Wraps an Upsonic Agent for SMTP/IMAP email via FastAPI.
  • MailTools (toolkit): Provides 17 agent-facing tools for email operations (send, receive, search, flag, delete, move, attachments).
  • InterfaceManager.serve: Serves the FastAPI app using Uvicorn.

MailInterface Interface

Main entry point for Upsonic Mail applications.

Initialization Parameters

ParameterTypeDefaultDescription
agentAgentRequiredUpsonic Agent instance.
namestr"Mail"Interface name.
smtp_hostOptional[str]NoneSMTP server hostname (or MAIL_SMTP_HOST).
smtp_portOptional[int]NoneSMTP server port (or MAIL_SMTP_PORT, default: 587).
imap_hostOptional[str]NoneIMAP server hostname (or MAIL_IMAP_HOST).
imap_portOptional[int]NoneIMAP server port (or MAIL_IMAP_PORT, default: 993).
usernameOptional[str]NoneEmail account username (or MAIL_USERNAME).
passwordOptional[str]NoneEmail account password (or MAIL_PASSWORD).
use_sslboolFalseUse SSL for SMTP instead of STARTTLS.
from_addressOptional[str]NoneSender address (defaults to username).
api_secretOptional[str]NoneSecret token for API authentication (or MAIL_API_SECRET).
modeUnion[InterfaceMode, str]InterfaceMode.TASKTASK or CHAT.
reset_commandOptional[str]"/reset"Text in email body that resets chat session (CHAT mode). Set None to disable.
storageOptional[Storage]NoneStorage backend for chat sessions (CHAT mode).
allowed_emailsOptional[List[str]]NoneWhitelist of sender emails; only these are processed. None = allow all.
mailboxstr"INBOX"IMAP mailbox/folder to poll.

Key Methods

MethodParametersReturn TypeDescription
attach_routesNoneAPIRouterReturns the FastAPI router and attaches all endpoints.
check_and_process_emailscount: int = 10CheckEmailsResponseTrigger email check and processing.
is_email_allowedsender: strboolWhether the sender is in the whitelist (or whitelist disabled).
health_checkNoneDictReturns interface health status with IMAP connectivity check.

Endpoints

Mounted under the /mail prefix. All endpoints require the X-Upsonic-Mail-Secret header if api_secret is configured.

POST /mail/check

  • Triggers a check for unread emails and processes them through the agent.
  • Query parameter: count (default: 10) - maximum number of emails to process.
  • In TASK mode: agent decides to reply or ignore each email.
  • In CHAT mode: emails are routed to per-sender conversation sessions.
  • Returns: 200 CheckEmailsResponse with status, processed_count, and email_uids.
curl -X POST http://localhost:8000/mail/check \
  -H "X-Upsonic-Mail-Secret: your-secret"

GET /mail/inbox

  • Lists the most recent emails (read and unread).
  • Query parameters: count (default: 20, max: 100), mailbox (default: INBOX).
  • Returns: 200 EmailListResponse with count and emails array.

GET /mail/unread

  • Lists unread emails only.
  • Query parameters: count (default: 20, max: 100), mailbox (default: INBOX).
  • Returns: 200 EmailListResponse with count and emails array.

POST /mail/send

  • Sends a new email.
  • Request body: to (string or array), subject, body, cc (optional), bcc (optional), html (optional boolean).
  • Supports single and multiple recipients.
  • Returns: 200 {"status": "success", "message": "..."}.
curl -X POST http://localhost:8000/mail/send \
  -H "X-Upsonic-Mail-Secret: your-secret" \
  -H "Content-Type: application/json" \
  -d '{
    "to": ["alice@example.com", "bob@example.com"],
    "subject": "Hello",
    "body": "Hello from Upsonic!",
    "cc": "manager@example.com"
  }'

POST /mail/search

  • Searches emails using IMAP search criteria.
  • Request body: query (IMAP search string), count (default: 10), mailbox (default: INBOX).
  • Returns: 200 EmailListResponse with matching emails.
curl -X POST http://localhost:8000/mail/search \
  -H "X-Upsonic-Mail-Secret: your-secret" \
  -H "Content-Type: application/json" \
  -d '{"query": "FROM \"user@example.com\"", "count": 5}'

GET /mail/folders

  • Lists all available mailboxes/folders on the IMAP server.
  • Returns: 200 {"status": "success", "folders": [...]}.

GET /mail/status

  • Gets the status of a mailbox (total, unseen, recent message counts).
  • Query parameter: mailbox (default: INBOX).
  • Returns: 200 MailboxStatusResponse with mailbox, total, unseen, recent.

POST /mail/{uid}/read

  • Marks an email as read by its UID.
  • Query parameter: mailbox (default: INBOX).
  • Returns: 200 {"status": "success", "uid": "...", "action": "marked_read"}.

POST /mail/{uid}/unread

  • Marks an email as unread by its UID.
  • Returns: 200 {"status": "success", "uid": "...", "action": "marked_unread"}.

POST /mail/{uid}/delete

  • Deletes an email by its UID.
  • Returns: 200 {"status": "success", "uid": "...", "action": "deleted"}.

POST /mail/{uid}/move

  • Moves an email to a different mailbox/folder.
  • Query parameter: destination (required), source (default: INBOX).
  • Returns: 200 {"status": "success", "uid": "...", "action": "moved", "destination": "..."}.

GET /mail/health

  • Health/status of the interface including IMAP connectivity check.