Repository navigation
Releases: remorses/zele
Release list
zele@0.10.0
-
Free, permanent
@zele.shemail addresses (receive-only for now). Sign in with a @gmail.com owner and create up to 10 addresses for yourself, a project, or your agents:zele login zele --owner you@gmail.com --name tommy zele inbox create bills zele inbox list zele mail list --account tommy@zele.sh
The sign-in code is read automatically from the owner Gmail when it is already a zele account; otherwise pass
--code. Each inbox works withmail list,mail read,mail search,mail watch, star, archive, trash, spam, and attachments. Sending, drafts, and labels return a clear "receive-only" error.zele logout zelesigns out and removes the inbox accounts from this machine. -
mail watchis now the way to wait for a reply after sending —mail sendandmail replyprint the exact watch command to run next:zele mail send --to bob@example.com --subject "Question" --body "Hey" # Wait for the reply: zele mail watch --account me@example.com --filter 'from:bob@example.com subject:"Question"' --timeout 259200
mail watchprints how long it waited: anelapsedfield on the match,Timed out after 3d 0h 0m 0son timeout, and# Still watching, 3m 0s elapsedon stderr every minutemail watchno longer exits on a network error. It prints# Poll failed ..., retryingand polls again, so a watch can run for days. Auth errors still stop it
-
Fixed
mail watchon Gmail returning an old email as a match — it reused a history cursor from an earlier run and replayed emails that arrived since then. Now only emails that arrive after the command starts can match, same as IMAP.
zele@0.9.0
-
Proton Mail Bridge and self-signed IMAP/SMTP servers —
login imapnow works with local TLS endpoints that use their own certificate:# Proton Bridge default (STARTTLS on 1143/1025), trusting the exported cert zele login imap \ --email you@proton.me \ --imap-host 127.0.0.1 --imap-port 1143 \ --smtp-host 127.0.0.1 --smtp-port 1025 \ --password "<bridge-password>" \ --no-tls --ca ~/bridge/cert.pem # Bridge SSL mode: both listeners use implicit TLS zele login imap \ --email you@proton.me \ --imap-host 127.0.0.1 --imap-port 1143 \ --smtp-host 127.0.0.1 --smtp-port 1025 \ --password "<bridge-password>" \ --smtp-tls --ca ~/bridge/cert.pem
--ca <path>trusts a PEM certificate, such as Bridge's exportedcert.pem--smtp-tlsforces implicit TLS on a custom SMTP port--insecureskips certificate verification. It is unsafe; prefer--ca--no-tlsdisables implicit IMAP TLS. STARTTLS is still used when the server offers it
-
New
label renamecommand — rename a Gmail label in place. The label keeps its ID and all its threads:zele label list zele label rename Label_12 Bookings
-
mail searchnow finds mail you sent — before, search looked only in Inbox. IMAP search now looks in Inbox and Sent; usein:sentorin:inboxfor one mailbox. Gmail search with no--foldernow searches all mail (spam and trash excluded). Results from both mailboxes are sorted by date across pages.mail list --folderstays on that folder even if the filter has a differentin:.zele mail search "to:alice@example.com" --limit 20 zele mail search "in:sent to:alice@example.com" --limit 20
-
No more hard-wrapped Gmail drafts — Gmail opened text-only drafts in its plain-text composer, which broke long paragraphs into ~78-column lines on send. Plain-text bodies are now sent with an HTML copy, so lines wrap naturally. Text like
Bob <bob@example.com>orVec<String>is no longer mistaken for HTML. This also fixes forwarded drafts losing their line breaks. -
mail label --addno longer creates junk labels — labels created or renamed outside zele were not found, so zele created duplicates, and a label ID likeLabel_12became a new label with that literal name. zele now matches label IDs as well as names, refreshes the label list before it treats a label as missing, and rejects unknownLabel_<n>IDs. -
Fixed
mail list --filter is:unread— it no longer returns read or sent threads, and it fills--limitwith real matches.fromis now the sender of the latest message, and threads where you sent the latest message showflags: sent.--label Workresolves label names. -
Fixed unreadable non-ASCII IMAP bodies — Chinese (UTF-8, GBK), Latin-1 accents and Windows-1252 punctuation now show correctly in quoted-printable, base64 and raw bodies.
Thanks @georgantas for #15, @yougeqiu for #16, @emanuelet for #18 and #19, and @Cvikli for finding the draft wrapping bug in #17!
zele@0.8.0
-
Importable mail SDK — apps can list, read, reply, and mutate mail without spawning the CLI.
import 'zele'now resolves todist/index.js:import { listMailThreads, readMailThread, messageToMarkdown, archiveMail, replyMail, } from 'zele' const listed = await listMailThreads({ folder: 'inbox', limit: 20 }) if (listed instanceof Error) throw listed const first = listed.threads[0] const thread = await readMailThread({ threadId: first.id, account: first.account, }) if (thread instanceof Error) throw thread console.log(messageToMarkdown(thread.messages[0]))
The same module also exports
starMail,unstarMail,trashMail,markMailRead,markMailUnread,getMailAttachment, pluslistAccountsandgetClientsfor the lower-level Gmail and IMAP clients. Functions returnError | Tinstead of throwing. -
IMAP/SMTP
--attachnow survives send —--attachalready reached SMTP, but the Sent-folder copy fell back to a plain-text RFC 822 body becauseMailComposeris not a public nodemailer export. Zele now compiles one MIME buffer withnodemailer/lib/mail-composerand uses that buffer for both SMTP DATA and IMAP Sent APPEND:zele mail send --account you@example.com --to peer@example.com \ --subject 'Invoice' --body 'Attached.' --attach ./invoice.pdf
zele@0.7.0
-
Microsoft OAuth for Outlook, Hotmail, and Microsoft 365 — connect Microsoft accounts without an app password:
zele login microsoft zele login microsoft --email you@outlook.com zele login --method microsoft
Outlook.com requires XOAUTH2 for IMAP and SMTP. Zele opens the Microsoft consent page, stores the resulting tokens, and refreshes access tokens before each connection so long-running commands such as
mail watchcontinue after the one-hour token expires.In agent and non-TTY environments, browser login starts as a background daemon and returns immediately. Approve the printed URL, then poll for the authenticated account:
zele login --method microsoft zele whoami
Outlook accounts appear as
imap_smtpinzele whoami. Mail commands work through IMAP and SMTP; Google-only labels, filters, and calendar commands remain unavailable.
zele@0.6.0
-
Safer
mail replyrecipients — replies used to go to the sender of the last message. When that last message was yours, the reply landed in your own inbox. Recipients now come from the thread: last non-draft message, parsedReply-To, and walk-back when you sent the last one.zele mail reply <thread-id> --dry-run zele mail reply <thread-id> --to paul@acme.com --body "…" zele mail reply <thread-id> --allow-self --body "…"
A reply that would only reach you is refused with
SelfRecipientError. Newzele mail send --thread-idsends into an existing thread with correctIn-Reply-To/References.zele mail send --thread-id <thread-id> --to paul@acme.com --cc dana@acme.com --body "…"
-
mail replyrequires a priormail read— agents can no longer reply from a stale thread view. If the latest message changed, the command fails withUnseenLatestError.--dry-runskips the check.--forceskips it too.zele mail read 18f3b7c9d2a1e4f0 zele mail reply 18f3b7c9d2a1e4f0 --body "sounds good"
-
Reliable local database — Prisma +
@prisma/adapter-libsqlcould acknowledge writes then roll them back on exit. That droppedThreadReadrows and refreshed OAuth tokens. The CLI now uses Drizzle withnode:sqlite. Existing~/.zele/sqlite.dbfiles keep working.CLI commands now need Node.js 22.16+.
zele@0.5.0
-
mail watchexits on first match —mail watchnow blocks until the first email matching the filter arrives, prints it, and exits with code 0. This makes it useful for agents that need to wait for a specific email (verification codes, replies, etc.). The--onceflag has been removed since the new behavior subsumes it.New
--timeoutflag sets a maximum wait time in seconds. If no matching email arrives before the deadline, the command exits with code 1:# wait for a reply from alice zele mail watch --filter "is:unread from:alice@example.com" # wait for a verification code with a 5-minute timeout zele mail watch --filter "is:unread subject:verification" --timeout 300
-
Attachment support for
mail reply— send file attachments with replies and draft replies via the--attachflag:zele mail reply <threadId> --body "See attached" --attach report.pdf zele mail reply <threadId> --body "Draft with attachment" --attach doc.pdf --draft
Works with both Gmail and IMAP/SMTP accounts. The
--attachflag is repeatable. -
Shell completions and goke framework alignment — install tab completions for zsh and bash via
zele completions install. AI agents (Claude, Cursor, Codex, etc.) are detected automatically and skip interactive prompts. Destructive commands now require--forcein non-TTY/agent mode. -
Interactive IMAP login —
zele login imapis now fully interactive in TTY mode: prompts for email, shows a provider preset selector (Fastmail, Gmail, Outlook, Custom) that auto-fills IMAP/SMTP hosts and ports, and prompts for password with masked input. -
Interactive prompts for
cal respondandlogout—cal respondprompts for accept/decline/tentative when--statusis omitted.logoutshows an account selector when multiple accounts are logged in. -
Atomic schema initialization — schema DDL and column migrations now run inside a single
BEGIN IMMEDIATEtransaction, acquiring the write lock once instead of 13+ separate transactions. EliminatesSQLITE_BUSYerrors when multiple CLI processes start concurrently. -
Fixed transient SQLITE_BUSY errors — concurrent process access no longer causes intermittent database busy errors. Thanks @Cyberlane for #13!
Closes #14
zele@0.4.0
-
Run CLI under Node.js — all CLI subcommands (
mail,cal,label, etc.) now work with plain Node.js v18+. The TUI auto-spawns bun when running under Node; if bun isn't installed, it shows install instructions:# CLI-only (no bun needed) npm install -g zele zele mail list --limit 100 # Full TUI support bun install -g zele zele
-
Fixed child signal propagation — when the TUI is terminated by a signal (Ctrl+C, SIGTERM), the parent process now re-raises the signal so the shell sees the correct exit status (130 for SIGINT, 143 for SIGTERM) instead of a generic exit code 1.
-
Preserved HTML comments in email rendering — HTML comments embedded in emails (like
<!-- metadata -->) now pass through the HTML-to-markdown conversion instead of being stripped. -
Fixed @opentui/react version mismatch — bumped
@opentui/coreand@opentui/reactfrom^0.1.88to^0.2.12to match termcast peer deps. Fresh installs were resolving an incompatible 0.1.x version, causing "Renderer not found" and React dispatcher crashes on TUI launch.
Fixes #12
zele@0.3.21
-
Polished interactive prompts — replaced raw readline prompts with
@clack/promptsacross auth, draft, calendar, and label commands. All confirmation dialogs and selects now have a clean, styled UI. -
--methodflag onzele login— skip the interactive prompt for non-interactive environments:zele login --method google zele login --method imap
Non-TTY environments without
--methodnow exit with a clear message instead of hanging. -
--limitreplaces--maxonmail list,mail search,cal events, anddraft list:zele mail list --filter "is:unread" --limit 100 zele mail search "from:github" --limit 100 zele cal events --limit 100
-
--filterreplaces--queryoncal events,draft list, andmail watch— now consistent withmail list:zele cal events --filter "standup" zele draft list --filter "invoice" zele mail watch --filter "from:github"
zele@0.3.20
-
--draftflag onmail replyandmail forward— save as draft instead of sending immediately:# Draft a reply with proper threading headers zele mail reply <threadId> --body "sounds good" --draft # Draft a reply-all zele mail reply <threadId> --body "sounds good" --all --draft # Draft a forward zele mail forward <threadId> --to colleague@example.com --draft
Full threading headers (
In-Reply-To,References) are set so the draft appears inside the original thread in Gmail. IMAP accounts write the headers into the raw MIME appended to the Drafts folder. -
draft update <draftId>— update an existing draft without touching unchanged fields:# Update just the body zele draft update <draftId> --body "updated text" # Pipe new body from stdin echo "new body" | zele draft update <draftId> --body-file - # Change recipients and subject zele draft update <draftId> --to new@example.com --subject "New subject"
Thread association and send-as alias are preserved automatically. IMAP uses delete + re-append (no native update in IMAP).
-
mail unsubscribe <threadId>— unsubscribe from mailing lists using RFC 2369 / RFC 8058 headers:zele mail unsubscribe <threadId> # auto: one-click → mailto → url zele mail unsubscribe <threadId> --dry-run # preview only zele mail unsubscribe <threadId> --via mailto zele mail unsubscribe <threadId> --then archive
One-click only triggers automatically when the message passes DKIM (spoofing guard). SSRF guard blocks requests to localhost and internal ranges.
-
can_unsubscribeandone_clickinmail list/mail search— every thread row shows whether a standardized unsubscribe mechanism is present. -
Fixed timeout on slow unsubscribe endpoints — one-click POST now times out after 10 s.
-
mail unsubscribetolerates 3xx redirects — many real senders redirect after processing the POST. Treated as success with a warning instead of failing.
zele@0.3.17
-
IMAP/SMTP account support — connect any email provider (Fastmail, Outlook, Gmail app passwords, or any IMAP server) alongside existing Google OAuth accounts:
# Fastmail zele login imap \ --email you@fastmail.com \ --imap-host imap.fastmail.com --imap-port 993 \ --smtp-host smtp.fastmail.com --smtp-port 465 \ --password "your-app-password" # Outlook zele login imap \ --email you@outlook.com \ --imap-host outlook.office365.com --imap-port 993 \ --smtp-host smtp-mail.outlook.com --smtp-port 587 \ --password "your-password" # IMAP-only (no sending) zele login imap \ --email reader@example.com \ --imap-host imap.example.com \ --password "pass"
All read/write mail commands work with IMAP accounts:
mail list,mail read,mail search,mail send,mail reply,mail forward,mail star,mail archive,mail trash,mail mark-read,draft list,draft send, etc. Google-only features (labels, filters, calendar) show a clear error when used with IMAP accounts.mail listandmail searchmerge results from Google and IMAP accounts automatically. RFC 6154 special-use folder detection means sent/drafts/trash resolve correctly across providers (including Outlook "Sent Items", localized Gmail folders, etc.).whoamishows account type and capabilities for each connected account. -
Email authentication verification (SPF/DKIM/DMARC) —
mail readnow shows structured auth verdicts per message:auth: spf=pass dkim=pass dmarc=pass ✓Use
--verifyto see the rawAuthentication-Resultsheader. Theauthenticboolean field is useful for agents acting on sensitive emails (e.g. subscription cancellations):zele mail read <thread-id> | yq '.messages[0].auth.authentic'