npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@bobfrankston/rmfmail

v1.2.140

Published

Local-first email client with IMAP sync and standalone native app

Readme

rmfmail -- Email Client

A local-first email client with IMAP sync, full offline reading, and a standalone native app. Replaces Thunderbird/Outlook.

Disclaimer: This is a personal project written for my own use. I provide it as-is with no promises of support, stability, or fitness for any particular purpose. Use at your own risk.

Renamed from @bobfrankston/mailx (2026-05). The old name collided with Linux's BSD mailx (/usr/bin/mailx) every launch in WSL or on a Linux box. If you have the old package, run npm install -g @bobfrankston/rmfmail && npm uninstall -g @bobfrankston/mailx. The old ~/.mailx/ config directory is auto-migrated to ~/.rmfmail/ on first start.

MIT License -- Copyright (c) 2026 Bob Frankston

Installation

npm install -g @bobfrankston/rmfmail
rmfmail

Requires Node.js 24.2 or later.

On Windows, the native WebView2 app launches automatically via IPC (no HTTP server needed).

Updating

Update with @bobfrankston/bobup — it lists and updates globally-installed @bobfrankston/* packages (cross-platform):

npm install -g @bobfrankston/bobup    # once
bobup                                 # update rmfmail + any other @bobfrankston tools to latest
bobup update rmfmail                  # update only rmfmail
bobup list                            # preview what's outdated first

After updating, restart the app to pick up the new version: rmfmail -kill then rmfmail. (Plain npm install -g @bobfrankston/rmfmail still works as well.)

Platforms

| Platform | Status | How it runs | |----------|--------|-------------| | Windows | ✅ | Native WebView2 window via the msger host (default); IPC, no HTTP server | | Linux | ✅ | msger host (WebKit WebView) | | macOS | ⏳ planned | msgview (Electron) host — set MAILX_HOST=msgview once the adapter ships | | Android | ✅ | Standalone MAUI app — its own local store + direct IMAP/Gmail sync; side-load the APK |

The host is chosen at runtime via @bobfrankston/mailx-host (override with the MAILX_HOST env var). The Android app is a full standalone client — not a remote view of the desktop — so it works with the desktop turned off.

--server (Express HTTP/browser) mode was removed (2026-06). The client became IPC-only, leaving the browser path with no transport, so the mode was dead. Use the native desktop app or the standalone Android app instead.

First-Time Setup

On first run, rmfmail shows a setup form. Enter your name and email address.

Gmail / Google Workspace

No password needed. rmfmail detects Gmail via MX records, opens a browser for OAuth2 sign-in, and auto-configures Google Drive for settings sync. Custom domains hosted on Google Workspace are detected automatically.

Outlook / Hotmail / Live

No password needed. OAuth2 sign-in opens in your browser.

Yahoo

Use an app password (not your regular password):

  1. Go to Yahoo Account Settings > Account Security
  2. Click Generate app password
  3. Paste the generated password into rmfmail

AOL

Use an app password:

  1. Go to AOL Account Settings > Account Security
  2. Click Generate app password
  3. Paste the generated password into rmfmail

iCloud

Use an app-specific password:

  1. Go to appleid.apple.com > Sign-In and Security
  2. Click App-Specific Passwords > Generate
  3. Paste the generated password into rmfmail

Other Providers (Dovecot, Fastmail, etc.)

Enter your IMAP password. rmfmail auto-detects server settings via MX records and DNS. If detection fails, use Manual setup (advanced) in the setup form, or create an accounts file and import it (see below).

Adding Accounts via File

You can create an accounts.jsonc file and import it into rmfmail. This is useful for adding accounts that aren't easily configured through the setup form (custom IMAP servers, non-standard ports, etc.).

Step 1. Create a file (e.g., my-accounts.jsonc) with your account(s):

{
  "accounts": [
    {
      "email": "[email protected]",
      "name": "Your Name",
      "label": "Work",                   // Display name in folder tree
      "imap": {
        "host": "imap.example.com",      // IMAP server hostname
        "port": 993,                     // 993 for TLS (default)
        "tls": true,
        "user": "[email protected]",       // IMAP username (default: email)
        "password": "your-password"
      },
      "smtp": {
        "host": "smtp.example.com",      // SMTP server hostname
        "port": 587,                     // 587 for STARTTLS (default)
        "tls": true,
        "user": "[email protected]",
        "password": "your-password"
      }
    }
  ]
}

For known providers, most fields are optional:

{
  "accounts": [
    { "email": "[email protected]", "name": "Your Name" },
    { "email": "[email protected]", "name": "Your Name", "password": "app-password-here" },
    {
      "email": "[email protected]",
      "name": "Your Name",
      "label": "Personal",
      "imap": { "host": "imap.yourserver.com", "user": "you", "password": "pass" },
      "smtp": { "host": "smtp.yourserver.com", "user": "you", "password": "pass" }
    }
  ]
}

Step 2. Import into rmfmail:

rmfmail --import my-accounts.jsonc

This merges the accounts into your Google Drive settings (deduplicates by email address). Existing accounts are preserved.

Gmail OAuth

No setup required for normal use — rmfmail ships with OAuth credentials, so the first Gmail connection just opens a browser for consent and tokens refresh automatically.

What to expect during Google sign-in:

  • The consent screen lists what rmfmail is asking for (Gmail, Google Drive, Contacts, Calendar) with checkboxes — every listed item must be checked. Google sometimes shows them unchecked by default; an unchecked item makes rmfmail repeat the sign-in later for the missing scope.
  • You may be sent to the browser more than once. Mail, settings storage (Drive), and contacts authorize separately, so two or three consent rounds on first setup is normal — each success page says so and closes itself after a few seconds.
  • If sign-in seems stuck, check for a browser window behind other windows waiting for you.

Advanced / self-hosting (optional): to use your own OAuth app instead of the bundled credentials, create a project in the Google Cloud Console, enable the Gmail API (and People API for contacts), create OAuth 2.0 credentials (Desktop app type), and save them as ~/.rmfmail/google-credentials.json. Outlook/Graph works the same way via ~/.rmfmail/microsoft-credentials.json.

Usage

Layout

A vertical icon rail sits on the far left (Thunderbird / Dovecot style) with one-click access to Compose, Inbox, All Inboxes, Contacts (Google address book), Calendar, Tasks, View options, and Settings. Calendar/Tasks open the right-side sidebar (Google Calendar + Tasks); Contacts opens the address book. The rail is always visible on wide and medium screens; it folds into the hamburger menu on narrow ones.

Reading Mail

  • Click a folder to see its messages
  • Click a message to read it in the preview pane
  • All Inboxes combines inboxes from all accounts (appears with 2+ accounts)
  • A small filled teal dot before the date means the message body is downloaded locally (offline-ready); a hollow circle means not yet prefetched. Prefetch runs as a background task every ~60 s independent of folder sync.
  • Unread counts show on folders; sub-folder counts bubble up to collapsed parents
  • Use the folder search box to find folders by name

Composing

  • Ctrl+N -- New message
  • Ctrl+R -- Reply
  • Ctrl+Shift+R -- Reply All
  • Ctrl+F -- Forward
  • From dropdown lets you pick which account to send from; reply auto-detects which identity to reply from based on which of your addresses the mail was sent to
  • Contact autocomplete searches Google Contacts as you type in To/Cc/Bcc
  • Cc / Bcc are hidden by default — click the toggle buttons next to To to show them
  • Attach opens a file picker; attachments show as chips with remove buttons
  • Drafts auto-save 1.5s after you stop typing, plus a 5s safety-net interval, plus on window close
  • Compose window close asks Save / Discard / Cancel if there's content
  • Address validation ([email protected]) runs on To/Cc/Bcc/From before sending — invalid addresses are refused
  • Editor shortcuts: Ctrl+K insert link, Ctrl+Shift+K remove link, Ctrl+Shift+X strikethrough, Ctrl+Shift+7/8 ordered/bullet list, Ctrl+]/[ indent/outdent, Ctrl+Shift+C color, Ctrl+\ clear formatting. Native spell-check via WebView2 (right-click to add to dictionary).
  • Link editor modal: Ctrl+K opens a two-field dialog (text + URL) with Remove-link button; hovering any link in the editor shows a floating URL preview
  • Paste URL auto-links: paste a bare URL over a selection and it wraps it, or paste into empty space to insert as a link

Managing Messages

  • Delete or Ctrl+D -- Delete selected messages (moves to Trash; second delete in Trash is a hard delete + EXPUNGE)
  • Ctrl+Z -- Undo the last delete or move (whichever came last, 60s window)
  • Ctrl+A -- Select all messages (enters multi-select; row avatars turn into checkboxes). Escape or a plain click exits multi-select.
  • Multi-select actions -- With rows selected, right-click → Flag/Unflag, Mark read/unread, or Move acts on the whole selection. Clicking the star on any selected row flags/unflags the entire selection at once.
  • R or Ctrl+Q -- Toggle read/unread on the focused message (bare R defers while typing in a field; Ctrl+Q always works). Auto mark-as-read (with a configurable delay) is on by default — see Settings.
  • Drag and drop -- Move messages to a folder by dragging them
  • Right-click a message → Move to folder… -- Searchable folder picker; useful on narrow layouts where the folder tree is hidden
  • Click the star column to flag/unflag a single message
  • Unsubscribe button appears when the message has a List-Unsubscribe header. One-click (RFC 8058) when the sender advertises List-Unsubscribe-Post: List-Unsubscribe=One-Click; otherwise opens the URL or a pre-filled compose for mailto: lists.
  • Right-click on a From/To/Cc address -- Copy name, Copy address, Copy both, Add to contacts, or Reply/Reply All/Forward
  • Right-click in the message body → Translate (opt-in) -- Uses the configured AI provider; select text first to translate just the selection. Off by default; enable under Settings → AI translate.
  • Preview pane zoom -- Ctrl+wheel, Ctrl+= / Ctrl+- / Ctrl+0, or right-click menu (Zoom in/out/reset, Copy, Select all). Persisted across messages.
  • Cross-folder search results show the folder name for each hit
  • Empty Trash / Empty Junk -- Right-click the folder in the tree → Empty (confirmation prompt)

Searching

Type in the search bar and press Enter. Use the dropdown to search:

  • All folders -- Every account and folder
  • This folder -- Current folder only (filters as you type, server search on Enter)
  • IMAP server -- Server-side search (useful for messages older than your sync window)

Supports regex: wrap pattern in /slashes/.

Search as find: selecting a result then closing the search (clear the box or press Escape) returns you to that message in its real folder, instead of bouncing back to where you started — so search doubles as a "jump to this message" tool. Search is ephemeral: it never persists across a restart. An empty result reads No messages found by "query" so it's clear the search (not the mailbox) is empty.

Folder Operations

Right-click a folder for options:

  • Mark all read
  • New subfolder
  • Rename / Delete folder
  • Empty (Trash and Junk only)

Drag a folder onto another to reparent it (server-side IMAP RENAME / Gmail label / Outlook move).

View Options

Under View in the toolbar:

  • Two-line view -- Show preview snippet below each subject
  • Preview pane -- Toggle the message reader panel
  • Preview snippets -- Show snippet text in message rows
  • Flag stars -- Show the grey ☆ on every row (on by default). Turn it off to hide empty stars; flagged ★ rows keep their gold star, and a row's ☆ reappears on hover so you can still click to flag.
  • Group by thread -- Collapse reply chains to the newest message with a count pill; click the pill for a popup of the whole conversation
  • Only this conversation -- Filter the list to the selected message's thread
  • Flagged only -- Show only starred messages (the list takes a flag-coloured wash so the filter is obvious). Session-only — resets on restart.
  • Priority senders only -- Show only mail from senders/domains marked priority in contacts.jsonc
  • Folder counts -- Show total message counts on all folders
  • Calendar sidebar -- Show the right-side calendar / tasks panel

Settings

Under Settings in the toolbar:

  • Editor -- Choose between Quill (default), tiptap, or TinyMCE for compose
  • External editor (Edit in Word) -- Open the compose body in Microsoft Word or LibreOffice Writer for heavy editing (Auto / Word / LibreOffice)
  • Auto mark-as-read -- Mark a viewed message read after a short, configurable delay (delay in seconds; 0 = immediately). Turn off to require an explicit Mark-read.
  • Check sender reputation (DNSBLs) -- When opening a message with remote content, look the sender's domain up in three free blocklists in parallel (off by default; each query leaks the bare domain to that DNSBL)
  • AI autocomplete -- Enable LLM-powered writing suggestions (Ollama, Claude, or OpenAI)
  • AI translate -- Enable the right-click Translate item in the message viewer (off by default; uses the same provider as autocomplete)
  • AI proofread -- Enable the proofread path (off by default; provider method available, UI wiring in progress)

All AI features are opt-in. Provider + API key live in the autocomplete settings; toggling a feature only controls whether that specific capability calls out to the provider.

Keyboard Shortcuts

| Key | Action | |-----|--------| | Ctrl+N | New message | | Ctrl+R | Reply | | Ctrl+Shift+R | Reply All | | Ctrl+F | Forward | | Delete / Ctrl+D | Delete | | Ctrl+Z | Undo last delete or move | | Ctrl+A | Select all (enter multi-select) | | R / Ctrl+Q | Toggle read/unread on the focused message | | F5 | Sync all folders | | Escape | Exit multi-select / clear search / close menus |

In the compose editor:

| Key | Action | |-----|--------| | Ctrl+K | Insert / edit link (opens dialog with text + URL fields) | | Ctrl+Shift+K | Remove link | | Ctrl+B / Ctrl+I / Ctrl+U | Bold / Italic / Underline | | Ctrl+Shift+X | Strikethrough | | Ctrl+Shift+7 / 8 | Ordered / Bullet list | | Ctrl+] / Ctrl+[ | Indent / Outdent | | Ctrl+Shift+C | Set text color | | Ctrl+\ | Clear formatting | | Ctrl+Enter | Send | | Escape | Close (prompts Save / Discard / Cancel) |

In the preview pane:

| Key | Action | |-----|--------| | Ctrl+wheel | Zoom in/out | | Ctrl+= / Ctrl+- | Zoom in / out | | Ctrl+0 | Reset zoom | | Delete | Delete message (also works with focus in preview) |

Command Line

Flag style: single-dash is canonical (-kill, -setup, ...). The parser also accepts double-dash (--kill, --setup) as a synonym, so older scripts that used --email / --import keep working.

rmfmail                        Start the app (native window via IPC)
rmfmail -email <addr>          First-time setup with this email (skips prompt)
rmfmail -verbose               Show log output in terminal (default: log file only)
rmfmail -import <file>         Import accounts.jsonc into Google Drive

rmfmail -kill                  Kill running rmfmail processes + clean up WAL files
rmfmail -setup                 Interactive first-time setup (CLI)
rmfmail -add                   Add another account (CLI)
rmfmail -test                  Test IMAP/SMTP connectivity for all accounts
rmfmail -repair                Re-sync message metadata, keep .eml files (fix garbled subjects)
rmfmail -rebuild               Wipe local cache and re-download everything from IMAP
rmfmail -recover               Rebuild the DB index from the .eml files on disk (no network)
rmfmail -fix-flags             Reconcile local ★ flags against the server's actual flagged set
rmfmail -reauth                Clear cached OAuth tokens; next start re-consents
rmfmail -log                   Print the log file path and exit
rmfmail -v                     Show version

rmfmail -send <file>           Enqueue a .ltr/.eml for sending. Daemon parses
                               the file's From: header to auto-route to a
                               configured account; falls back to the first
                               "override" account (non-known-provider domain).
rmfmail -send <file> -account <id>
                               Same, but force the account.

rmfmail -register-mailto       Register rmfmail as a Windows mailto: handler
rmfmail -unregister-mailto     Remove the mailto: handler registration

-send

Drop a raw .ltr or .eml file into the outbox without going through compose. Two paths under the hood:

  • rmfmail -send <file> copies into ~/.rmfmail/outbox/<basename> (general outbox). The running daemon's outbox sweep parses From: and routes the file into outbox/<accountId>/ based on:

    1. exact match against an account's email,
    2. known-provider domain match (gmail.com → first Gmail account; outlook.com / hotmail.com / live.com → first Outlook account),
    3. first account on a non-known-provider domain (the "override" account).
  • rmfmail -send <file> -account <id> skips routing and copies directly into ~/.rmfmail/outbox/<id>/.

Bcc handling: the file's Bcc: header is preserved on disk. The SMTP path (Gmail accounts) strips it from the wire bytes and adds the Bcc addresses to the SMTP envelope; the IMAP-Outbox path (Dovecot/etc.) uploads the file intact and lets the server-side outbox-drain sieve do the strip.

The CLI exits immediately. If the daemon isn't running, the file queues until next launch. To send right now, also run rmfmail (or have a daemon already running) — the outbox sweep ticks every 10 s.

Mailto handler (Windows)

rmfmail -register-mailto writes the HKCU registry keys so rmfmail appears in the Windows "Select an app to open this 'mailto' link" picker (and in Settings → Apps → Default apps). The picker entry launches %LOCALAPPDATA%\rmfmail\bin\rmfmailto.exe which shells out to the rmfmail daemon with the parsed mailto URL.

To make rmfmail the active default for mailto (rather than just a candidate), open Settings → Apps → Default apps, search for rmfmail, and click "Set default" for the mailto link type. Windows 11 enforces a hash on the UserChoice key so this final step can't be automated without MSIX packaging or a hash-aware helper.

rmfmail -unregister-mailto removes the registration. Run this before -register-mailto if the picker is showing a stale "Node.js JavaScript Runtime" entry from an older install.

-repair vs -rebuild vs -recover

-repair clears message metadata (subjects, flags, sender names) from the database but preserves your downloaded .eml message files. Folder sync state resets so rmfmail re-fetches all envelopes on next run. Use this when subjects show garbled characters.

-rebuild deletes the entire database and message store, then re-downloads everything from IMAP. Accounts and settings are preserved. Use this for a clean start or to reclaim disk space.

-recover rebuilds the database index purely from the .eml files already on disk — no network. Use it to get back everything you had after a DB loss when you'd rather not re-download from the server.

Configuration

All config files live in ~/.rmfmail/ (on Windows: C:\Users\You\.rmfmail\). On first start, an existing ~/.mailx/ directory is auto-renamed to ~/.rmfmail/.

config.jsonc (per-machine, not synced)

Points to shared settings and controls local behavior. Created automatically for Gmail accounts.

{
  "sharedDir": { "provider": "gdrive", "path": "rmfmail", "folderId": "..." },
  "storePath": "C:/Users/You/.rmfmail/mailxstore",
  "historyDays": 90,
  "accountOverrides": {
    "work": { "historyDays": 7 },
    "archive": { "enabled": false }
  }
}

sharedDir can be:

  • { "provider": "gdrive", "path": "rmfmail" } -- Google Drive via API (auto-configured for Gmail). The legacy folder names mailx and home/.mailx are also discovered automatically for users migrating from the old name.
  • "C:/Users/You/OneDrive/home/.rmfmail" -- Local/network path

accounts.jsonc (shared via Google Drive or local)

For known providers, only email is required -- IMAP/SMTP settings fill automatically.

{
  "accounts": [
    { "email": "[email protected]", "name": "Your Name" },
    { "email": "[email protected]", "name": "Your Name", "password": "xxxx-xxxx-xxxx-xxxx" },
    {
      "email": "[email protected]",
      "name": "Your Name",
      "label": "Work",
      "spam": "_spam",                    // Optional: enables the ⚠ Spam button in the viewer toolbar
      "imap": { "host": "imap.example.com", "port": 993, "tls": true, "user": "you", "password": "..." },
      "smtp": { "host": "smtp.example.com", "port": 587, "tls": true, "user": "you", "password": "..." }
    }
  ]
}

Optional per-account fields:

| Field | Type | Purpose | |-------|------|---------| | spam | string | IMAP folder path to send messages when the Spam (⚠) button is pressed. The button is hidden until this is set. Use the exact folder path on the server (e.g., "_spam", "INBOX/Spam", "[Gmail]/Spam"). | | label | string | Display name in the folder tree (overrides auto-detected). | | defaultSend | bool | Use this account's SMTP when From doesn't match any account. | | relayDomains | string[] | Domains to skip in Delivered-To chain (e.g., ["m.connectivity.xyz"]). | | deliveredToPrefix | string[] | Strip these prefixes from Delivered-To to recover the clean alias (e.g., ["bobf-ma-", "bobf-"] — order matters, longest first). | | identityDomains | string[] | Domains where Delivered-To becomes the reply From (e.g., ["bob.ma"]). |

Auto-detected providers:

| Domain | IMAP | SMTP | Auth | Label | |--------|------|------|------|-------| | gmail.com | imap.gmail.com:993 | smtp.gmail.com:587 | OAuth2 | Gmail | | outlook.com, hotmail.com | outlook.office365.com:993 | smtp.office365.com:587 | OAuth2 | Outlook | | yahoo.com | imap.mail.yahoo.com:993 | smtp.mail.yahoo.com:587 | App password | Yahoo | | aol.com | imap.aol.com:993 | smtp.aol.com:587 | App password | AOL | | icloud.com | imap.mail.me.com:993 | smtp.mail.me.com:587 | App password | iCloud |

Google Workspace and Microsoft 365 custom domains are detected automatically via MX records.

preferences.jsonc (shared)

{
  "ui": { "theme": "dark", "editor": "quill", "fontSize": 15 },
  "sync": { "intervalMinutes": 5, "historyDays": 30 },
  "autocomplete": {
    "enabled": false,
    "provider": "ollama",
    "ollamaUrl": "http://localhost:11434",
    "ollamaModel": "qwen2.5-coder:1.5b"
  }
}

allowlist.jsonc (shared)

Remote content (images, tracking pixels) is blocked by default. Whitelist trusted senders:

{
  "senders": ["[email protected]"],
  "domains": ["example.com"],
  "recipients": ["[email protected]"]
}

Multi-Machine Setup

Settings sync via Google Drive API. Each machine has its own config.jsonc:

Desktop (full history):

{ "sharedDir": { "provider": "gdrive", "path": "rmfmail" }, "historyDays": 0 }

Laptop (recent only):

{ "sharedDir": { "provider": "gdrive", "path": "rmfmail" }, "historyDays": 30,
  "accountOverrides": { "archive": { "enabled": false } } }

Both machines share accounts, preferences, and allowlist via Google Drive.

Data Storage

| Path | Synced? | Purpose | |------|---------|---------| | config.jsonc | No | Local config pointer + overrides | | accounts.jsonc | Yes | IMAP/SMTP account configs | | preferences.jsonc | Yes | UI and sync settings | | allowlist.jsonc | Yes | Remote content allow-list | | mailx.db | No | SQLite metadata (headers, contacts, sync state) | | mailxstore/ | No | Cached message bodies (.eml per message) | | logs/ | No | Daily log files |

Note: the SQLite database file (mailx.db) and message-store directory (mailxstore/) keep their original filenames inside ~/.rmfmail/ — they're internal to the app and renaming them would break backwards compatibility for no user benefit.

Safe to delete: mailxstore/ (re-downloaded on sync), mailx.db (re-created on startup), logs/ (anytime).

Logs

Daily log files: ~/.rmfmail/logs/mailx-YYYY-MM-DD.log

Use rmfmail --verbose to see logs in the terminal instead.

Troubleshooting

Blank window or no response -- Run rmfmail -kill then rmfmail to restart.

OAuth timeout -- If the browser auth window doesn't appear or times out (5 minutes), close rmfmail and try again.

Garbled subjects -- Run rmfmail -repair to re-sync metadata from IMAP.

Sync stuck or corrupt data -- Run rmfmail -rebuild for a clean start. Accounts and settings are preserved.

"Too many connections" -- rmfmail uses up to 5 IMAP connections per account. Close other email clients if you hit your server's limit.

App password rejected (Yahoo/AOL/iCloud) -- Make sure you're using an app-specific password, not your regular login. Generate a new one from your account security settings.

Agent API (apps and AI processing your mail)

A running daemon publishes ~/.rmfmail/agent.json — loopback RPC endpoint, SSE event stream, and two scoped tokens:

  • triage — reads, search, message bodies, flagging, mark-read. Safe default for AI.
  • full — the entire service surface (move, delete, drafts, send). Guard it accordingly.

POST {rpcUrl}?t={token} with {"_action": "searchMessages", "_cbid": "1", ...params} — the same dispatcher the UI uses, so anything the app can do, an agent can do. GET {eventsUrl}?t={token} streams daemon events (new mail, folder changes) as SSE for reactive agents.

MCP: rmfmail-mcp (installed with the package) exposes this as Model Context Protocol tools — claude mcp add rmfmail -- rmfmail-mcp and Claude can list/search/read/flag your mail; set RMFMAIL_MCP_FULL=1 on the server entry to add move + draft creation. By design there is no send tool: AI drafts, you send.

Architecture

  • IPC-first -- Default mode uses msger (Rust/WebView2) with bidirectional IPC. No TCP server, no CLOSE_WAIT zombies.
  • Host abstraction -- rmfmail talks to the WebView host through @bobfrankston/mailx-host, which picks msger (default) or msgview (Electron, planned for Mac and niche Linux) at runtime. Override with MAILX_HOST=msger|msgview. Internal package names retain the historical mailx-* prefix; only the public package was renamed.
  • Local-first -- Changes update local DB immediately; background worker syncs to IMAP.
  • Offline reading -- Full message bodies cached as .eml files.
  • IMAP IDLE -- Instant new-mail notifications + periodic sync fallback.
  • Outbox -- Queued in IMAP Outbox folder with multi-machine interlock via flags.
  • Remote content blocking -- HTML sanitized server-side, CSP in iframe, per-sender allow-list.
  • Search -- SQLite FTS5 full-text index + IMAP server search + regex filtering.
  • Connection management -- Semaphore limits 5 connections per account; exponential backoff on server limits.
  • Cloud sync -- Google Drive API for settings portability (no filesystem mount required).