A fast web-based mail client (IMAP/SMTP) built with Bun, TypeScript, and Next.js.
I am trying to combine the advantages of GMail, Thunderbird and Spark, step by step, keeping full IMAP compatibility using IMAP (custom) properties and relying on standard email headers for all features.
A working WebCal integration is planned, I need it, and it will be the first thing I will be working on after the mail client is stable and usable for daily use.
Automatic message categorization into Newsletter, Notification, and Transactional using a hybrid approach:
- Heuristic classifier based on robust mail headers and content signals
- Per-account online learning from manual category actions (set/change/clear)
- Manual override controls directly in the message action menu
- Debug visibility for learned model state and feedback events in Account Settings β Categorization
See doc/CATEGORIZATION.md for technical details.
Local topic tagging for threads with lightweight learning from your past assignments:
- Manual topic assignment from the message menu for projects, interests, or workflows
- Learned suggestions based on sender, recipient, and mailing-list signals from previously tagged threads
Discover connections across your inbox with related mails. When viewing any email, instantly find related messages based on:
- Subject similarity β Find conversations on similar topics
- Sender/Recipient overlap β Track communications with the same people
- Thread references β Follow email chains using In-Reply-To and References headers
- Calendar invite UID matches β Find invitation updates/cancellations tied to the same event
Access via the "Show related" option in the message action menu or search with related:<mail-id>. For calendar invites, use invite:<uid> (or event:<uid>) to find related invitation mails.
Built-in Model Context Protocol (MCP) support lets AI clients work with your mailbox through a structured, documented tool interface:
- Search and retrieval tools β Query messages, folders, topics, and mailing list aliases
- AI-friendly schemas β Discover tool inputs and outputs through MCP
tools/list - Actionable workflows β Create drafts and use mailbox data from external AI assistants without scraping the UI
Unified conversation threading that works across all folders. Whether emails are in Inbox, Sent, or any other folder, Noctua Mail intelligently groups them into cohesive threads. Collapse and expand conversations with ease, maintaining context no matter where messages are stored.
Built-in virtual folders keep triage fast and actionable:
- Focused β Prioritized inbox view for what matters now
- Action Queue β Messages that are flagged, marked TODO, or marked done
- Invite Deck β Calendar invitation-focused view with unread/total counters
Schedule reminders directly from ICS invites and get desktop/system notifications at the right time:
- Per-invite reminder controls β Schedule, modify, and delete reminders from the invite preview
- Recurring invite support β Reminder timing follows recurring event rules (
RRULE+ exceptions) - Automatic invite update handling β Reminder records are updated/removed when invite updates or cancellations arrive
- Offline-aware delivery β PWA/service worker delivery with local cache and due-lookback handling
Write emails in Markdown with a dedicated compose mode and send them as fully rendered HTML (with plain-text fallback), while preserving clean markdown source in drafts.
Simple, secure authentication using your existing IMAP credentials. No separate user accounts and no stored passwords to manage β just connect with your email server credentials and start using Noctua Mail immediately.
- IMAP sync β Full folder and message synchronization
- SMTP support β Send and reply to emails
- Multiple accounts β Manage several email accounts
- Rich message viewing β HTML, Text, Markdown, and Source views
- Attachments β Inline display and downloadable files
- Calendar invites β Display ICS details (full calendar support in progress π )
- Calendar reminders β Schedule notifications for invite events, including recurring meetings
- Automatic invite updates β Apply invite changes/cancellations to existing reminder data
- Three-pane layout β Folders, message list, and message view
- Dark mode π β Easy on the eyes
- Installable PWA π± β Install as a native app on desktop
- OS notifications π β Get notified of new emails
- Responsive design β Resizable panes with independent scrolling
- Per-message text scaling β Adjust font size (or zoom for HTML) for individual messages
- Virtualized lists β‘ β Blazing-fast display of thousands of emails
- Workflow folders β Focused, Action Queue, and Invite Deck virtual views
- Full-text search powered by SQLite FTS5
- Field filtering β Search by
from:(evenfrom:me),to:,subject:, and more - Related mail search β Find connected conversations with
related:<mail-id> - Invitation mail search β Find invite-related mails via
invite:<uid>(orevent:<uid>) - Search across all folders β Or narrow down to specific folders
- Intelligent conversation grouping β Automatically thread related messages
- Cross-folder threading β See complete conversations regardless of folder location
- Collapse/expand threads β Focus on what matters
- Visual thread indicators β Clear hierarchy and relationships
- Runtime β Bun
- Framework β Next.js (App Router)
- Language β TypeScript
- UI β Radix UI + Lucide Icons
- Email β ImapFlow + Nodemailer
- Database β SQLite (bun:sqlite) with FTS5 full-text search
- Rich Text β Lexical
- Bun runtime installed
bun install
bun run devOpen http://localhost:3654 in your browser.
Noctua Mail can also be packaged as a native desktop app using Tauri. See doc/DESKTOP.md for setup, development, and packaging instructions.
Run all tests:
bun testRun only the message list behavior regression tests:
bun test app/components/mailclient/messagelist/listBehavior.test.tsLocal data is stored in .data/ directory:
- SQLite database
- Message sources
- Attachments (stored separately for performance)
Configure how IMAP/SMTP credentials are stored:
IMAP_CREDENTIALS_STORAGE=both # Options: cookie | db | both (default: both)cookieβ Credentials only in sealed session cookiedbβ Credentials only in encrypted databasebothβ Credentials in both cookie and encrypted database (recommended)
IMAP_SECRET_KEY=<32-byte-hex-key> # Required for DB encryptionControl access to the application:
SESSION_SEAL_KEY=<32-byte-hex-key> # Required for session cookie sealingThe rate limiter (applied to /api/auth/login, /api/auth/signup, /api/probe) keys
requests by client IP. Since Request doesn't expose the TCP peer, it relies on
X-Forwarded-For, which means the reverse proxy in front of Noctua must sanitise
that header so a client can't spoof their own rate-limit identity.
Noctua assumes one trusted reverse proxy in front by default (no env var needed).
The recommended Caddy configuration uses the global trusted_proxies directive,
which instructs Caddy to ignore any X-Forwarded-For the client tries to send
and insert the real remote IP instead:
{
servers {
trusted_proxies static private_ranges
}
}
yourdomain.tld {
reverse_proxy localhost:3654
}If you need a different topology, use TRUSTED_PROXY_HOPS to override the default.
The value is the number of reverse-proxy hops whose X-Forwarded-For entry Noctua
should trust:
TRUSTED_PROXY_HOPS=1 # Default β single reverse proxy in front (no need to set this)
TRUSTED_PROXY_HOPS=2 # Two chained trusted proxies (e.g. Cloudflare β Caddy β Noctua)
TRUSTED_PROXY_HOPS=0 # Noctua directly on a public interface; ignore XFF entirely1(default) β rightmostX-Forwarded-Forentry (the IP the proxy saw) is used.N β₯ 2β the entry atXFF[length - N]is used. Requires at leastNentries inXFF; if fewer are present (topology mismatch), the request falls back to the"unknown"global bucket rather than trusting a potentially client-supplied leftmost entry.0/falseβ forwarded headers are ignored; rate limiting becomes a single global bucket per limiter. Coarse, but safe when Noctua is exposed directly.
Customize the data directory location:
NOCTUA_DATA_DIR=../noctua-data # Default: .data/- Desktop-optimized β Installable as a PWA, the UI is currently optimized and targeted for desktop use. Mails for mobile devices are better managed in a real app instead of a browser based webmail client. Mobile support will be improved over time, but it is not the primary focus.
This project is licensed under the Elastic License 2.0.
You are free to:
- β Use, modify, and distribute this software
- β Host it yourself for personal or commercial use
You may not:
- β Provide the software to third parties as a managed cloud service (SaaS)
Contributions are welcome! Feel free to open issues or submit pull requests.
The code is primarily written by AI agents (Claude, Codex, GitHub Copilot, Antigravity).
Built with β€οΈ and π€ by Paul Wellner Bou
