Connect data sources

Email (IMAP)

An email connection gives an AI client read access to one mailbox over IMAP: it can list folders, list and search emails, read an email's text, and fetch its attachments. When a token allows it, the client can also save a plain-text draft in the mailbox's Drafts folder for you to send yourself. It cannot send, delete, move, or mark mail.

Email needs no extra service: Postgres and the web app are enough.

Add the connection

Choose Email (IMAP) under Add a connection and fill in the server, port, security, username, and password. Presets fill in the server for Gmail, iCloud, Fastmail, Zoho, and Yahoo. Automata logs in with the credentials before saving anything, so a wrong password fails the create instead of leaving a connection that never syncs.

  • Use an app password. Gmail (with 2-Step Verification on), iCloud, Fastmail, Yahoo, and Zoho issue passwords meant for exactly this, and you can revoke one without changing your main password.
  • Microsoft 365 and Outlook.com cannot be connected. Microsoft no longer accepts passwords over IMAP and requires OAuth, which this connection does not support.
  • There is no unencrypted option. Choose TLS (usually port 993) or STARTTLS (usually 143). STARTTLS is enforced: a server that does not upgrade the connection is refused rather than sent the password in clear. Certificates are verified against the host name.

Change credentials on the connection's page replaces them, checked the same way. Every connector token keeps working. If the new login is a different mailbox, everything synced from the old one is deleted first.

What is stored

Only headers are synced. Bodies and attachments stay on your mail server and are fetched when a tool asks for them.

DataWhere it comes fromStored by Automata
Folders, sender, recipients, subject, date, read and flagged state, threading idsSynced every two minutesYes, about 1 KB per email
Attachment names, types, and sizesSynced from the message structureYes
Email bodyFetched when read-email asksNo
Attachment contentFetched when get-email-attachment asksNo, neither in the database nor on disk
Searching inside email textPassed to the mail server's own searchNo

Storage stays small however much mail you have. Folders are opened read-only and fetched with BODY.PEEK, so reading an email does not mark it read in your mail client.

Synced headers live in the app database (app.mail_folders, app.mail_messages, app.mail_sync_state) and are deleted with the connection. Like every connection credential, the mailbox password is stored in clear in the app database and its backups.

Sync behavior

  • Every folder except All Mail, Junk, and Trash is synced. Gmail's All Mail would hold every message a second time. Skipped folders still appear in list-mail-folders with synced: false, as do folders that cannot hold mail, such as a parent Archive above Archive/2024.
  • New mail arrives within two minutes, along with changes to read and flagged state. On servers with CONDSTORE the server reports what changed; on others the newest 500 emails per folder are re-checked each run.
  • Deleted mail is removed at least every ten minutes.
  • Older mail is backfilled newest first, 500 emails per folder per run, up to NUXT_IMAP_BACKFILL_DAYS (default 365) back and NUXT_IMAP_BACKFILL_MAX (default 50,000) emails per folder. A folder that stopped at a limit says so, and the tools tell the client that reaching the end of a listing means "oldest synced email", not "oldest email".
  • A folder the server renumbers (its UIDVALIDITY changes, as when a folder is deleted and recreated) is synced again from scratch. An email id issued before that asks the client to list the folder again instead of returning a different message.
  • One email in several folders, as with Gmail labels, is listed once with every folder it is in.
  • An email whose headers cannot be stored, because of malformed text the database refuses, is listed by date with no subject, sender, or attachments instead of stalling the rest of the folder. Its body is still readable.

The dashboard shows when the sync last succeeded, how far each folder has got, and why it is failing if it is. A refused password stops the sync until the credentials are changed or Sync now is pressed, since retrying a refused login every two minutes is how providers lock accounts. Listings say when the sync is behind, so a client does not present a stale inbox as current.

The mail server's replies are size-capped, and connecting plus logging in must finish within 60 seconds. A server that exceeds either fails that run without affecting other connections.

The sync runs in the web process and is safe with several replicas: each mailbox is claimed with a lease in the database, so only one replica syncs it at a time. A process that stops mid-sync holds the lease for up to ten minutes, during which Sync now reports that a sync is already running.

Tools and limits

ToolWhat it does
get-mailbox-statusWhich mailbox, whether the sync works, when it last ran, and which folders are still backfilling or stopped at a limit
list-mail-foldersFolders in scope, INBOX first, with synced and unread counts
list-emailsOne page of headers, newest first, from one folder or every synced folder in scope
search-emailsfrom, to, and subject against synced headers, and text through the mail server's search, combined with AND
read-emailHeaders, the body as plain text, and the attachment list
get-email-attachmentOne attachment: images as images, text files as text, anything else as an embedded file
create-email-draftWrite. Saves an unsent plain-text draft in the Drafts folder

Parameters for each tool are in the MCP tools reference.

  • Body search depends on your server. Most IMAP servers match substrings; Gmail matches whole words with its own search syntax. A search covers at most 20 folders within 25 seconds, and any folder it did not reach is named in the result.
  • Bodies are fetched up to 2 MiB. A longer body is cut there and read-email says so.
  • Text attachments are clipped at 100,000 characters, and the result says when one was.
  • Attachments are capped at NUXT_IMAP_ATTACHMENT_MAX_BYTES (default 10 MiB). A larger file is refused with its size before anything is downloaded, and the cap is enforced again on the bytes received. Only parts the synced message lists as attachments can be fetched.

Drafts

create-email-draft writes one message into the mailbox's Drafts folder, flagged as a draft and as read, and does nothing else. It cannot send mail: the connection has no SMTP credentials. The draft waits in your mail client until you send, edit, or delete it.

  • Off by default. A new email token starts with the six read tools allowed and create-email-draft not.
  • The folder is not the client's choice. It is the folder your server marks as Drafts, or failing that the one folder named "Drafts". A mailbox with neither, or with more than one, is refused rather than guessed at.
  • Plain text only, no attachments. The sender is the login address, so a connection whose username is not an email address cannot save drafts.
  • Replies are threaded. Given the id of the email being answered, the draft carries its In-Reply-To and References headers, the subject defaults to Re: …, and the recipient defaults to the original sender (or its recipients, when you sent the original). The original text is not quoted unless the client includes it.
  • The draft appears in list-emails after the next sync; saving one starts a sync straight away.

Folder scope

An email token is scoped by folder, the same way WhatsApp and Telegram tokens are scoped by chat. A token limited to Clients lists, searches, and reads only emails filed there: an email that is also in INBOX is reachable through its Clients copy only, and asking for a folder outside scope is refused by name. Saving drafts needs the Drafts folder in the allowlist. See Permissions for the rest of a token's scope.

Private network targets

The mail server is an address a user chose, so it passes the same outbound guard as a PostgreSQL connection string. Private and loopback addresses are refused unless NUXT_ALLOW_PRIVATE_TARGETS=true, this deployment's own backends are always refused, and the address approved is the one dialled. A cached connection's host is re-checked every minute.

Settings

All three are optional and set on the web service.

VariableDefaultPurpose
NUXT_IMAP_BACKFILL_DAYS365How far back the header sync reaches, per folder
NUXT_IMAP_BACKFILL_MAX50000Most emails synced per folder
NUXT_IMAP_ATTACHMENT_MAX_BYTES10485760Largest attachment get-email-attachment fetches
View source