Repository navigation
This release adds the JavaScript client, an IMAP inbox and MCP, and makes the server safe by default. Several defaults changed; read Changed before upgrading.
Added
mail-debugger/client: a typed ESM client for the REST API without dependencies, for Node.js and browsers.createApiClient(baseUrl, { token, headers, timeoutMs, fetch })offershealth,listEmails(positional or{ filter, limit, offset }),getEmail,getRawEmail,getAttachment,waitForEmail,deleteEmailanddeleteAllEmails, with abort signals, a 10-second default timeout and the errorsMailDebuggerApiError,MailDebuggerNetworkErrorandMailDebuggerTimeoutError. The root importmail-debuggeris not exported.- REST API:
GET /api/emails/waitwaits for the first matching email above a cursor (up to 60 seconds);GET /api/emails/:id/rawreturns the exact source bytes;GET /api/emails/:id/attachments/:indexdownloads one attachment. List responses carry the cursorhighWatermarkandmailboxId, emails carry the SMTPenvelopeincluding Bcc recipients, andGET /api/healthreportsversion,imapPortandmcp. mail-debugger cli: the terminal client as a command of the main package, with the newlist --limit/--offsetandwait(exit code 1 on timeout), JSON output and exit codes 0, 1 and 2.mail-debugger serveis the explicit form of the server command.- IMAP inbox with
--imapand--imap-port(1143, or 1993 with--tls implicit): one sharedINBOXthat mail clients and IMAP libraries can read, flag and expunge, with changes shared with every other surface. It is a restricted RFC 3501 profile: no other mailboxes, noAPPEND,COPY,MOVEorCREATE, no IMAP4rev2, CONDSTORE or QRESYNC; at most 20 sessions; development loginmail-debugger/mail-debuggerunless--auth-useris set. Desktop clients are documented setup targets; the tests use ImapFlow and raw protocol transcripts. Seedocs/imap.md. - MCP for AI agents with
--mcp: streamable HTTP at/mcpwith six read-only tools (list_emails,search_emails,get_email,wait_for_email,list_email_attachments,get_email_attachment);--mcp-allow-mutationsaddsdelete_emailandclear_emails.MAIL_DEBUGGER_MCP_TOKENrequires a bearer token.mail-debugger mcp --url <url>is a stdio bridge for clients that start processes. Limits: stateless (no sessions), results up to 1 MiB, attachments in chunks of up to 64 KiB, 32 pending waits and 64 requests at once; 2025-era HTTP clients cannot cancel a running wait, which then ends at its timeout of at most 30 seconds. Seedocs/mcp.md. - Options
--host,--data-dir,--tls-certand--tls-key,--auth-userwithMAIL_DEBUGGER_AUTH_PASSWORDor--auth-password-file,--allow-insecure-auth,--max-message-bytes,--max-messages,--max-storage-bytes,--http-allowed-host,--http-allowed-origin,--helpand--version. Port0picks a free port; the bound ports are logged and reported by the health endpoint. MAIL_DEBUGGER_API_TOKENprotects the REST API with a bearer token; the web inbox asks for it and keeps it in memory only.- The license text in all three packages, this changelog, a contributing guide, a code of conduct and a security policy.
Changed
- Node.js 22.17.0 or later is required (was 20).
- All listeners bind
127.0.0.1instead of every interface.--hostchooses another address; anything but loopback is refused unless SMTP and IMAP use TLS, mail clients authenticate with--auth-user,MAIL_DEBUGGER_API_TOKENis set and, with--mcp,MAIL_DEBUGGER_MCP_TOKENis set. - HTTP requests must carry an allowed
Hostheader and, if present, an allowedOrigin; others get 403. - Unknown, repeated or malformed options exit with code 2 instead of being ignored. A port in use exits with code 1.
- REST errors are objects,
{ "error": { "code", "message" } }, instead of strings.GET /api/emailsreturns at most 50 emails unlesslimit(1 to 200) is given;offsetalso works withoutlimit. Text filters match literally and case-insensitively, date bounds are inclusive and validated, and timestamps are UTC ISO 8601 with milliseconds. - Email ids are never reused, also after deleting all mail.
- Persistent storage:
--persistkeepsmail-debugger.sqlitein the working directory,--data-dirin another one. A 0.3 database is migrated on the first start after a backup copy (mail-debugger.sqlite.schema1.bak); message bytes that 0.3 could not store as UTF-8 stay replaced. Changes are coalesced into atomic snapshots scheduled 250 ms after the first pending change, and flushed on shutdown. Only one server can use a directory at a time; an existing lock always prevents startup and must be removed manually after checking that no process uses the directory. - New mail is refused once a limit is reached instead of being stored without bound: 552 above
--max-message-bytes(25 MiB), 452 at--max-messages(1000) or--max-storage-bytes(250 MiB). SMTP advertisesSIZE. - With
--auth-user, SMTP requires that account, over TLS unless--allow-insecure-authis given; without it, any credentials are still accepted. - The terminal client connects to
http://127.0.0.1:3000by default, reads its token fromMAIL_DEBUGGER_API_TOKEN, rejects unknown, repeated or misplaced options, and exits with code 2 instead of starting the interactive inbox when there is no terminal. mail-debugger-clidepends only on@rezi-ui/native, which ships prebuilt binaries, and installs 2 packages instead of 7 (5.7 MiB instead of 74 MiB).- The OpenAPI document is generated by
@elysiajs/openapi, at the same/swaggerand/swagger/jsonpaths. - The packages are built, tested as installed tarballs and published by CI with npm provenance.
Fixed
- Message sources are stored as the exact bytes SMTP received; 0.3 stored decoded text, which changed bytes that were not UTF-8.
- New mailbox data sets use a clock-independent, nonzero 32-bit UIDVALIDITY, avoiding deterministic reuse during rapid in-memory restarts; persistent stores retain their identity.
- UID exhaustion refuses new mail before
UIDNEXTwould overflow its 32-bit IMAP range; deleting mail never resets the allocation counter. - Static files of the web inbox are resolved strictly inside its directory, with the same rules on every platform; directories are not served.
- The help of
mail-debugger-apino longer mentions a web inbox.
Security
- The HTML preview of the web inbox runs with a Content-Security-Policy that blocks scripts, requests, frames and form submissions; remote images load only on request, with consent scoped to the current message and preview content.
- Terminal output replaces control characters of captured mail and command-line diagnostics, so escape sequences cannot act on the terminal.
- Attachment and source downloads are served with safe content types,
X-Content-Type-Options: nosniffand a sandboxing Content-Security-Policy. - Passwords and tokens are compared in constant time and never logged.