Email adapter — an agent's mail senses & hands
Mail joins the modality set: read a mailbox, perceive new mail as it arrives (sense), and send — over raw IMAP/SMTP or the Gmail API.
Raw IMAP/SMTP — no new dependency
IMAPDriver(scheme=imap):fetchreads a mailbox by UID cursor;sensedelta-polls for new mail (UID > cursor,modality="message").SMTPDriver(scheme=smtp):writecomposes a MIME message (to/cc/bcc/html/reply_to) and sends it.- Runs the stdlib
imaplib/smtplibinasyncio.to_thread— the event loop never blocks, app-password auth needs nothing extra. EmailDiscovery:imap://→ a read+sense endpoint per mailbox;smtp://→ an/outboxsend endpoint.
OAuth2 (XOAUTH2)
- Reusable
OAuth2TokenProvider(liquid.auth.oauth2) factored out of the HTTP flow so the mail sockets reuse the same refresh + vault-storage outside httpx; refresh-once-and-retry on auth failure. auth_schemethreaded intoWriteContext/SenseContext(mirroringFetchContext) so any non-HTTP driver sees the scheme on write/sense.
Gmail REST
GmailDriver(scheme=gmail):fetchlists + hydrates messages,writeposts a base64url MIME tomessages.send,sensedelta-pollshistory.list. Rides the shared httpx client + the OAuth2httpx.Auththe Fetcher already builds (401 refresh for free).gmail://me@host→/messages(read+sense) +/messages/send(write),oauth2/ tier-A.
Surface parity holds automatically: mail read endpoints emit list_/sense_ tools via to_tools(); send surfaces through liquid_execute.
Real-world reach now also: email (IMAP/SMTP + Gmail).