Skip to content

Development

Anton Popov edited this page Nov 10, 2026 · 1 revision

Development

Layout

Path What
server/ the Express server: sessions, IMAP/SMTP, routes (routes/), contacts, calendar, tasks, rules (Sieve), S/MIME, admin helpers
web/src/ the React + Vite front end (App.tsx, Calendar.tsx, Tasks.tsx, SidePanel.tsx, …)
web/src/locales/ one file per language
ops/ helper scripts for the mail server (goodmail-setpw, goodmail-admin)
deploy/ example systemd unit, Apache vhost, the "be right back" page
test/ unit tests (Node's built-in test runner)
scripts/screenshots/ regenerates the README screenshots from a fake mailbox

Commands

npm run dev        # API on :3000 + Vite on :5173 (Node >= 23.6)
npm test           # unit tests + a live-server smoke test
npm run typecheck  # tsc over server, web and tests
npm run build      # dist/ + dist-server/index.mjs

The S/MIME tests skip themselves when openssl with cms is missing.

Adding a language

Copy one of the files in web/src/locales/, translate the values and register it in web/src/i18n.ts. The English text is the key, so anything untranslated falls back to English. The i18n test checks that {placeholders} match and that no translation is empty.

Storage

All per-user data is small JSON files written atomically (tasks/, calendar/, contacts/, prefs/, …) through a per-user queue, so no database is needed. See Data and Backups.

README screenshots

scripts/screenshots starts a fake IMAP/SMTP/ManageSieve server with invented demo mail, contacts, events and tasks, and drives headless Chrome through the interface:

cd scripts/screenshots && npm install
npm run demo &
(cd ../.. && npm run build && NODE_ENV=production GOODMAIL_INSECURE_COOKIE=true PORT=3100 \
  GOODMAIL_OPENSSL=/opt/homebrew/bin/openssl GOODMAIL_CONFIG=scripts/screenshots/demo.conf \
  GOODMAIL_DATA=$(mktemp -d) node dist-server/index.mjs) &
npm run capture

Start from a fresh data folder and a fresh npm run demo each time. GitHub caches README images, so bump the ?v= tag in the README image links after regenerating.

Contributing and licence

Issues and pull requests are welcome. goodmail is AGPL-3.0-or-later: if you run a modified version for other people over a network, offer them the source of your version, and point the in-app "Source code" link at your fork with GOODMAIL_SOURCE_URL.

Clone this wiki locally