1
0
Fork 0
mirror of https://github.com/root-fr/jmap-webmail.git synced 2026-05-13 22:32:58 -04:00
Modern JMAP webmail client built for Stalwart Mail Server. Privacy-focused, responsive, with real-time updates. https://root.cloud/projects/jmap-webmail
  • TypeScript 98.9%
  • CSS 0.9%
  • JavaScript 0.1%
Find a file
Matthieu MALVACHE f3e84a9549
fix: v1.5.1 - Gmail-origin attachments render, email-to-self delivered
- Attachments from providers that stamp a Content-ID on every part
  (e.g. Gmail) now show in the attachment panel; previously they were
  silently filtered out as "inline" even when the HTML body never
  cited their cid. The viewer now parses the body for actual cid:
  references and treats only those attachments as inline (#58).
- Email-to-self no longer gets discarded as a duplicate by the
  sender's own MTA. The send flow keeps the outgoing message in
  Drafts during submission and uses EmailSubmission.onSuccessUpdate\
Email to move it to Sent only after SMTP has accepted it, so the
  inbound delivery for self-send doesn't match a pre-existing
  Message-ID in the account (#60).

Thanks @melges-morgen and @tamisoft for the reports.
2026-04-17 14:58:11 +02:00
.github/workflows feat: v1.5.0 - print, archive-thread, favicon badge + avatars, ru/uk locales 2026-04-17 14:39:50 +02:00
.husky feat(calendar): add event notifications with alert evaluation 2026-02-16 23:49:35 +01:00
app feat: v1.5.0 - print, archive-thread, favicon badge + avatars, ru/uk locales 2026-04-17 14:39:50 +02:00
components fix: v1.5.1 - Gmail-origin attachments render, email-to-self delivered 2026-04-17 14:58:11 +02:00
contexts feat: v1.4.0 - folder management, mail multi-selection, bug fixes 2026-03-23 15:24:46 +01:00
e2e feat: add contacts phase 2, advanced search, vacation responder, Docker & TOTP 2FA 2026-02-16 18:51:30 +01:00
hooks feat: v1.5.0 - print, archive-thread, favicon badge + avatars, ru/uk locales 2026-04-17 14:39:50 +02:00
i18n feat: v1.5.0 - print, archive-thread, favicon badge + avatars, ru/uk locales 2026-04-17 14:39:50 +02:00
lib fix: v1.5.1 - Gmail-origin attachments render, email-to-self delivered 2026-04-17 14:58:11 +02:00
locales feat: v1.5.0 - print, archive-thread, favicon badge + avatars, ru/uk locales 2026-04-17 14:39:50 +02:00
public Initial release: JMAP Webmail Client 2025-12-10 17:54:22 +01:00
screenshots feat: Search pagination and UX improvements 2025-12-17 18:39:49 +01:00
stores feat: v1.5.0 - print, archive-thread, favicon badge + avatars, ru/uk locales 2026-04-17 14:39:50 +02:00
.dockerignore feat: add contacts phase 2, advanced search, vacation responder, Docker & TOTP 2FA 2026-02-16 18:51:30 +01:00
.env.example feat: add contacts phase 2, advanced search, vacation responder, Docker & TOTP 2FA 2026-02-16 18:51:30 +01:00
.gitignore Initial release: JMAP Webmail Client 2025-12-10 17:54:22 +01:00
CHANGELOG.md fix: v1.5.1 - Gmail-origin attachments render, email-to-self delivered 2026-04-17 14:58:11 +02:00
CONTRIBUTING.md Initial release: JMAP Webmail Client 2025-12-10 17:54:22 +01:00
docker-compose.yml chore(docker): use pre-built GHCR image in docker-compose 2026-02-21 23:57:39 +01:00
Dockerfile fix(docker): resolve 4 CVEs in production image 2026-02-26 13:39:57 +01:00
eslint.config.mjs feat: add contacts phase 2, advanced search, vacation responder, Docker & TOTP 2FA 2026-02-16 18:51:30 +01:00
instrumentation.node.ts fix: details toggle UX, Edge Runtime warnings, minimatch CVE 2026-02-28 21:03:02 +01:00
instrumentation.ts fix: details toggle UX, Edge Runtime warnings, minimatch CVE 2026-02-28 21:03:02 +01:00
LICENSE Initial release: JMAP Webmail Client 2025-12-10 17:54:22 +01:00
next.config.ts feat: add server-side version update check 2026-02-28 14:59:11 +01:00
package-lock.json fix: v1.5.1 - Gmail-origin attachments render, email-to-self delivered 2026-04-17 14:58:11 +02:00
package.json fix: v1.5.1 - Gmail-origin attachments render, email-to-self delivered 2026-04-17 14:58:11 +02:00
playwright.config.ts feat: add contacts phase 2, advanced search, vacation responder, Docker & TOTP 2FA 2026-02-16 18:51:30 +01:00
postcss.config.mjs Initial release: JMAP Webmail Client 2025-12-10 17:54:22 +01:00
proxy.ts feat: add contacts phase 2, advanced search, vacation responder, Docker & TOTP 2FA 2026-02-16 18:51:30 +01:00
README.md feat: v1.5.0 - print, archive-thread, favicon badge + avatars, ru/uk locales 2026-04-17 14:39:50 +02:00
ROADMAP.md fix: v1.5.1 - Gmail-origin attachments render, email-to-self delivered 2026-04-17 14:58:11 +02:00
tailwind.config.ts Initial release: JMAP Webmail Client 2025-12-10 17:54:22 +01:00
tsconfig.json Initial release: JMAP Webmail Client 2025-12-10 17:54:22 +01:00
VERSION fix: v1.5.1 - Gmail-origin attachments render, email-to-self delivered 2026-04-17 14:58:11 +02:00
vitest.config.ts feat: add contacts phase 2, advanced search, vacation responder, Docker & TOTP 2FA 2026-02-16 18:51:30 +01:00
vitest.setup.ts feat: add contacts phase 2, advanced search, vacation responder, Docker & TOTP 2FA 2026-02-16 18:51:30 +01:00

JMAP Webmail

A webmail client for Stalwart Mail Server, built with Next.js and the JMAP protocol.

Why Stalwart?

Stalwart is a mail server written in Rust with native JMAP support, not IMAP/SMTP with JMAP added as an afterthought. It handles JMAP, IMAP, SMTP, and ManageSieve. Self-hosted, no third-party dependencies.

Stalwart on GitHub | Documentation

Features

Email

  • Read, compose, reply, reply-all, and forward
  • HTML rendering with DOMPurify sanitization and sandboxed iframe for complex emails
  • Attachment upload and download
  • Draft auto-save with discard confirmation
  • Threading with inline expansion
  • Mark as read/unread, star/unstar
  • Archive and delete with configurable behavior
  • Color tags/labels with sidebar counts
  • Search with JMAP filter panel, search chips, cross-mailbox queries
  • Virtual scrolling for large lists
  • Empty folder (one-click empty Junk/Trash with batch progress)
  • Sender info panel (click sender name to view contact, add to contacts, search)
  • API retry with exponential backoff for transient failures

Interface

  • Three-pane layout with dark and light themes
  • Responsive (desktop sidebar + mobile bottom tab bar + mobile action bar)
  • Keyboard shortcuts
  • Drag-and-drop email organization
  • Multi-select emails (checkboxes, shift-click) with batch move/delete toolbar
  • Folder management (create, rename, move, delete) from sidebar context menu
  • Drag-and-drop folder reparenting
  • Right-click context menus (long-press on touch devices)
  • Extra-compact, compact, regular, and comfortable density options
  • Resizable sidebar (drag, touch, keyboard)
  • Animations that respect prefers-reduced-motion
  • Infinite scroll pagination
  • Toast notifications with undo support
  • Form validation with shake feedback
  • Safe area insets for notched devices
  • Screen reader live regions

Real-time

  • Push notifications via JMAP EventSource
  • Live unread counts
  • Email arrival notifications
  • Connection status indicator

Identity management

  • Multiple sender identities with per-identity signatures
  • Sub-addressing (user+tag@domain.com) with tag suggestions
  • Identity badges in viewer and list

Address book

  • Contact management with search and filtering
  • JMAP server sync (RFC 9553/9610) with local fallback
  • Email autocomplete in composer
  • Contact groups with group expansion
  • vCard import/export (RFC 6350) with duplicate detection
  • Bulk operations (multi-select, delete, group add, export)

Calendar

  • JMAP Calendar (RFC 8984) with capability detection
  • Month, week, day, and agenda views
  • Event create, edit, delete with recurrence and reminders
  • Participant scheduling with iTIP invitations and RSVP
  • Inline calendar invitation banner in email viewer (.ics detection, RSVP, import)
  • Multi-day events, column-based overlap layout
  • Mini-calendar sidebar with calendar visibility toggles
  • Locale-aware date formatting
  • Settings for first day of week, time format (12h/24h), default view
  • Drag-and-drop rescheduling with time snap
  • Click-drag on empty slots to create events
  • Resize events by dragging (15-minute snap)
  • Double-click quick create
  • Event duplication (+1 day offset)
  • Recurring event edit/delete scope (this, this and following, all)
  • iCalendar (.ics) file import with preview
  • Real-time updates via JMAP push
  • Event notifications with configurable sound

Email templates

  • Reusable templates organized by category
  • Placeholder variables ({{recipientName}}, {{date}}, etc.) with auto-fill
  • Template picker in compose toolbar with search and filter
  • Template manager in settings

Email filters

  • Server-side filtering with JMAP Sieve Scripts (RFC 9661)
  • Visual rule builder: conditions (From, To, Subject, Size, Body...) and actions (Move, Forward, Mark read, Star, Discard, Reject...)
  • Raw Sieve editor with syntax validation
  • Auto-save with rollback on failure
  • Drag-and-drop rule reordering
  • Only shown when the server supports Sieve

Vacation responder

  • JMAP VacationResponse with date range scheduling
  • Settings tab for message configuration
  • Sidebar indicator when active

Security and privacy

  • External content blocked by default
  • Trusted senders list for automatic image loading
  • HTML sanitization (DOMPurify)
  • SPF/DKIM/DMARC status indicators with plain-language tooltips
  • Session-based auth, no password storage by default
  • TOTP two-factor authentication
  • "Remember me" with AES-256-GCM encrypted httpOnly cookie (opt-in)
  • OAuth2/OIDC with PKCE for SSO (opt-in, RP-initiated logout)
  • External IdP support (Keycloak, Authentik) via configurable issuer URL
  • CORS misconfiguration detection with detailed error messages
  • Shared folder support
  • Newsletter unsubscribe (RFC 2369)
  • CSP, X-Content-Type-Options, X-Frame-Options, Referrer-Policy headers

Internationalization

  • 8 languages: English, French, Japanese, Spanish, Italian, German, Dutch, Portuguese
  • Automatic browser language detection
  • Persistent language preference

Deployment

  • Pre-built Docker images on Docker Hub and GHCR (amd64/arm64)
  • Multi-stage build with standalone output
  • Runtime environment variables (no rebuild needed)
  • Health check endpoint
  • Structured logging (text/JSON)
  • Update check on startup (server logs only, no client exposure)

Tech stack

Getting started

Prerequisites

  • Node.js 18+
  • A JMAP-compatible mail server (Stalwart recommended)

Installation

git clone https://github.com/root-fr/jmap-webmail.git
cd jmap-webmail
npm install
cp .env.example .env.local

Configuration

Edit .env.local:

# App name displayed in the UI
APP_NAME=My Webmail

# Your JMAP server URL (required)
JMAP_SERVER_URL=https://mail.example.com

These are runtime environment variables, read at request time. Docker deployments can be configured without rebuilding. Legacy NEXT_PUBLIC_* variables still work as fallbacks.

OAuth2/OIDC (optional)

To enable SSO login alongside Basic Auth:

OAUTH_ENABLED=true
OAUTH_CLIENT_ID=webmail
OAUTH_CLIENT_SECRET=              # optional, for confidential clients
OAUTH_ISSUER_URL=                 # optional, for external IdPs (Keycloak, Authentik)

Endpoints are auto-discovered via .well-known/oauth-authorization-server or .well-known/openid-configuration. If your JMAP server delegates auth to an external IdP, set OAUTH_ISSUER_URL to the IdP's base URL (e.g., https://keycloak.example.com/realms/mail).

To disable Basic Auth:

OAUTH_ONLY=true

Remember me (optional)

To enable "Remember me" for Basic Auth login:

SESSION_SECRET=your-secret-key    # Generate with: openssl rand -base64 32

When set, a "Remember me" checkbox appears on the login form. Credentials are encrypted with AES-256-GCM and stored in an httpOnly cookie (30-day expiry).

Development

npm run dev        # Start dev server
npm run typecheck  # Type checking
npm run lint       # Linting

Production

npm run build
npm start

Docker

# Pre-built image
docker run -p 3000:3000 -e JMAP_SERVER_URL=https://mail.example.com rootfr/jmap-webmail:latest

# From GHCR
docker run -p 3000:3000 -e JMAP_SERVER_URL=https://mail.example.com ghcr.io/root-fr/jmap-webmail:latest

# With docker compose
cp .env.example .env.local
# Edit .env.local with your JMAP_SERVER_URL
docker compose up -d

# Build from source
docker build -t jmap-webmail .
docker run -p 3000:3000 -e JMAP_SERVER_URL=https://mail.example.com jmap-webmail

Keyboard shortcuts

Key Action
j / k Navigate between emails
Enter / o Open selected email
Esc Close viewer / deselect
c Compose new email
r Reply
R / a Reply all
f Forward
s Toggle star
e Archive
# / Delete Delete
u Mark as unread
/ Focus search
x Expand/collapse thread
Ctrl+Shift+T Insert template
? Show shortcuts help

Screenshots

Login Login

Inbox Inbox

Email Viewer Email Viewer

Compose Compose

Dark Mode Dark Mode

Settings Settings

Contributing

See CONTRIBUTING.md for guidelines.

Roadmap

See ROADMAP.md for planned features.

Acknowledgments

License

MIT. See LICENSE.