Skip to content

isi1988/Mailfold

Repository files navigation

Mailfold

CI Go Report Card Docker Hub GitHub release License: PolyForm Noncommercial 1.0.0

A modern web frontend (admin panel + webmail) for mailcow-dockerized.

Website: mailfold.site

Mailfold — the name plays on two meanings: a fold is both the crease of a letter (mail) and an enclosure for livestock, nodding to mailcow's cattle branding and the "herd" of domains and mailboxes the panel manages.

Stack

  • Backend: Go — a thin, typed API layer on top of the mailcow REST API.
  • Frontend: React (Vite) — an admin panel and a built-in webmail client, served by the backend as a single-page app.

All code and documentation are written in English.

Contents

Authentication & access

Mailfold recognizes three separate kinds of sign-in, all from the same login screen: a single set of credentials is checked against every kind in parallel, whichever matches decides where you land, and if more than one matches you're simply asked which to open.

  • Admin — the super-admin account (MAILFOLD_ADMIN_USER/_PASSWORD) gets the full panel.
  • Webmail — any mailcow mailbox address + its password signs straight into a clean, standalone webmail. A user can hold several mailboxes at once and switch between them.
  • Domain admin — mailcow's own scoped administrators (limited to a subset of domains) get a real login into Mailfold itself, not just mailcow's SOGo/admin UI. Setting or changing a domain admin's password from the "New domain admin" drawer also registers it for this separate sign-in. Once in, a domain admin manages single sign-on for the domain(s) mailcow currently reports them scoped to.

On top of password sign-in:

  • Single sign-on (OIDC) — one or more identity providers can be configured from the UI (not a fixed environment variable), each scoped either to every domain or to a specific set. A super-admin's shared providers are available everywhere; a domain admin can add their own, scoped to just the domain(s) they manage. A successful sign-in authenticates into the one mailbox whose address matches the provider's verified identity — never the admin panel.
  • Device sign-in with an API key — paste a personal API key instead of a password to sign a new device into webmail. Useful for a mail client, script, or phone that only holds a key. Any active key works regardless of its declared scopes, since the app-password behind every key is always fully IMAP+SMTP capable.
  • Two-factor authentication (TOTP) — the admin and any webmail mailbox user can each independently enroll their own optional TOTP 2FA (QR code + one-time recovery codes) from their own settings; sign-in gains a second-factor step once it's on.
  • Account security & recovery — the admin can change their password, edit their profile, and review/revoke active sessions (by device/IP, individually or all at once) from Settings. A "forgot password?" link emails a reset link from a mailbox the admin configures themselves (see MAILFOLD_ADMIN_ENC_KEY), not a fixed environment variable.

Mail

A built-in three-pane webmail client (folders · message list · reader):

  • Message previews, star, flag, archive, delete, attachment download, and live new-mail notifications over SSE.
  • Compose is a rich-text editor (bold/italic/lists/links, sending HTML); sent mail is saved to Sent, and folders and labels can be created inline.
  • Multi-account — hold several linked Mailfold mailboxes in one place and switch between them, or connect an external IMAP mailbox (Gmail, Yandex, …) that syncs into the same inbox.
  • Rules — simple "if sender/recipient/subject contains X, move to folder Y" automation, backed by mailcow's Sieve filters, configured from webmail settings.
  • Signatures — a personal signature added automatically to new messages, replies, and forwards.
  • Collapsed quote history — a long back-and-forth thread doesn't pile up as an ever-growing wall of quotes: the reader collapses everything past the 3 most recent quoted messages behind a "show N earlier" toggle, and reply/forward generate a proper quoted header instead of a bare > prefix.
  • Opening webmail from inside the admin panel hides the admin sidebar for a distraction-free reading view, with a button back to the panel; an admin opening a mailbox they hadn't opened before is asked whether to keep it linked to their account or just view it once.

Calendar & contacts

Mailfold ships self-hosted CardDAV and CalDAV servers so contacts, calendars, and tasks can be stored and synced without SOGo, backed by a local SQLite database (MAILFOLD_DB_PATH).

  • CardDAV endpoint: /dav/carddav/ (discovery at /.well-known/carddav).
  • CalDAV endpoint: /dav/caldav/ (discovery at /.well-known/caldav), supporting events (VEVENT) and tasks (VTODO).
  • Authentication: HTTP Basic with the user's own mailbox credentials (verified against IMAP, then cached briefly).

Point a standard client (Thunderbird, iOS/macOS Contacts & Calendar, DAVx⁵) at the endpoints to sync, or use the built-in calendar in webmail: a Mail / Calendar toggle opens a full Month / Week / Day view with a sidebar (mini-month, calendar legend, upcoming list) and drag-to-reschedule. Recurring events expand across the view, multi-day events span their days, and a detected meeting link surfaces a Join-call button. The event editor covers all-day and timed events, guests, recurrence, reminders and file attachments; events are colour-coded by calendar (work / personal / team / holidays), and clicking one opens a detail card with an Outlook-style RSVP row (Going / Maybe / Can't).

Admin panel

Run the whole mailcow server from one calm UI:

  • Dashboard — container health, storage, mail queue at a glance.
  • Mailboxes — quotas, a usage bar, last login, per-mailbox app passwords, Sieve filters, rate limits and temporary aliases in a slide-over drawer, plus bulk creation from a CSV file.
  • Domains — a detail page per domain with DKIM key management, rate limits, and a live DNS check that verifies MX, the mail host's A record, SPF, DKIM and DMARC against the live zone.
  • Aliases — a mailbox-picker for recipients and a catch-all-for-domain toggle.
  • Mail queue — flush for redelivery, or discard everything outright.
  • Quarantine — release or delete held messages.
  • Spam policy — per-domain allow/block lists, plus custom Rspamd rule blocks for finer-grained scoring and whitelisting.
  • Sync jobs — IMAP/POP import, with a move-instead-of-copy option.
  • Logs — per-service, with an "All services" merged view and a live-tail toggle.
  • Fail2ban and Settings (theme, accent, language).
  • Advanced — the niche routing/config resources: relay hosts, transports, TLS policies, forwarding hosts, BCC/recipient maps, and domain/mailbox templates.
  • Administration — delegated admins, domain admins, SSO providers, and OAuth2 clients.

API & SDKs

API keys — drive your mailbox from other apps. Issue durable, individually-revocable API keys so any third-party service can send and collect mail for a mailbox over a simple REST API — without ever handling the mailbox password. A key is a thin bearer handle in front of a mailcow application password scoped to IMAP + SMTP only; the app-password is encrypted at rest (AES-256-GCM) and the plaintext token is shown exactly once, at creation.

Enable it with MAILFOLD_APIKEY_ENABLED=true and a MAILFOLD_APIKEY_MASTER_KEY (≥32 bytes, hex or base64). It reuses MAILFOLD_DB_PATH for storage and stays off until both are set.

  • Admin (normal session) mints/lists/revokes keys: POST/GET /api/apikeys, DELETE /api/apikeys/{id}. Revoking a key also deletes its upstream app-password.
  • The key itself authenticates the machine surface with Authorization: Bearer mf_live_…:
    • Send (mail:send): POST /api/v1/mail/sendFrom is forced to the bound mailbox (no spoofing), with recipient and body-size caps.
    • Collect (mail:read): GET /api/v1/mail/folders|messages|message|search|attachment.
    • Mutate (mail:write): POST /api/v1/mail/flag, DELETE /api/v1/mail/message.
    • The same key can also sign into webmail directly on a new device, in place of the mailbox password.

Requests are rate-limited per source IP (before authentication) and per key (defaults: 120 requests/minute per key, 50 recipients per send, 1MB combined text+HTML body — all tunable via MAILFOLD_APIKEY_RATE_MAX, MAILFOLD_APIKEY_RATE_WINDOW, MAILFOLD_APIKEY_MAX_RECIPIENTS), and all token verification is constant-time.

Why an API instead of talking SMTP/IMAP directly?

You can always drop down to raw SMTP and IMAP — Mailfold doesn't hide or disable them. The API exists because, for the integrations most people actually build (a service that sends notifications and occasionally reads a reply), it removes work SMTP/IMAP push onto every caller:

  • One credential, one endpoint, both directions. SMTP alone can only send. Reading needs a second protocol, a second library, and a second credential — the API key does both over the same HTTPS endpoint.
  • Never touches the real mailbox password. A key fronts a scoped mailcow app-password. Leak one key and you revoke that one key — nothing else breaks, and the mailbox password never changes.
  • Scoped and individually revocable per integration. Mint a mail:send-only key for a contact-form mailer, a mail:read-only key for a ticket importer, and so on — instead of every integration sharing one all-or-nothing mailbox password.
  • Guardrails you'd otherwise build yourself. Recipient caps, a body-size cap, per-IP and per-key rate limiting, and CRLF/header-injection rejection on every field are enforced server-side, not left as an exercise for each client.
  • Plain HTTPS gets through firewalls that block mail ports. SMTP (587/465) and IMAP (993) are routinely blocked by corporate egress rules, CI runners, and some cloud providers — including, at one point, the very server Mailfold's own reference deployment runs on. Port 443 almost always works.
  • No protocol/session state to manage. No STARTTLS handshake, no IMAP SELECT/IDLE state machine, no connection pooling — every call is one stateless, safely-retryable HTTP request.
  • Structured JSON, not raw MIME. Messages, folders, and attachments come back already decoded into typed fields, instead of something your code has to parse out of the wire format yourself.
  • Official, maintained SDKs in three languages — see below — instead of hunting for (or hand-rolling) a decent SMTP+IMAP library pair per language.

What an API key can and can't do

The key-authenticated surface is a thin, safe layer over the operations most integrations need — send and collect, not a full IMAP/SMTP replacement. Concretely, with an API key you can:

  • Send a message (plain text and/or HTML) and list, search, read, flag, or permanently delete messages in any folder of the one mailbox it's bound to.

You cannot, with an API key alone:

  • Attach files when sendingPOST /api/v1/mail/send takes a subject and text/HTML body only, no attachments. (Downloading an attachment from a received message is supported.)
  • Move a message between folders, or create a new folder — those are webmail-session-only operations.
  • Read or write calendars/contacts — CardDAV/CalDAV authenticate with the mailbox's real IMAP password over HTTP Basic, not an API key.
  • Get pushed new-mail notifications in real time — the SSE stream needs a webmail session token; with an API key, poll messages/search instead.
  • Touch any mailbox other than the one the key is bound to, or perform admin operations (creating mailboxes, configuring domains) — those need the separate admin session, a different authentication tier entirely.
  • Read or change the mailbox's signature/rules — those are also webmail-session-only settings.

If an integration outgrows the API-key surface, it doesn't need a second credential: the same key can be exchanged once for a full webmail session via device sign-in, which unlocks everything above.

Official client SDKs

Official, minimal client libraries wrap this API for you — mint a key in the admin panel and start sending/collecting mail in a few lines. All three are published and installable right now:

Language Repository Package
Python isi1988/mailfold-python pip install mailfold-clientPyPI (zero third-party dependencies)
Go isi1988/mailfold-go go get github.com/isi1988/mailfold-gopkg.go.dev (zero third-party dependencies)
Rust isi1988/mailfold-rust cargo add mailfoldcrates.io

Each repository has its own README with a full quickstart. For any other language, the REST surface is small enough to call directly — see below.

API documentation

The running server documents itself:

Internationalization

Every user-facing string goes through a translation layer; the UI ships in English today, and adding a language is a single drop-in locale file.

Domains in a non-Latin script (e.g. родоскоп.рф) are stored by mailcow in punycode (xn--d1amkbbgbl.xn--p1ai); Mailfold decodes them back to readable Unicode everywhere they're shown, and normalizes either form to punycode before IMAP/SMTP authentication and in every outgoing recipient address, so a mailbox works the same — logging in, sending, and receiving — whether you type its address in Cyrillic or in punycode.

Architecture

React SPA  ──▶  Mailfold Go backend  ──▶  mailcow API (/api/v1/...)

The Go backend authenticates to mailcow with an API key, exposes a clean REST surface to the frontend, and serves the built SPA.

Editions (open-core)

Mailfold is open-core. The community edition in this repository is complete and self-contained; it stores its groupware and API-key data in SQLite and needs no external database. The persistence layer is a small driver registry (backend/storage), so the same store code runs on more than one database with no duplication.

The enterprise edition adds a PostgreSQL backend for larger, multi-node deployments. It is a separate, private Go module that imports this core and registers a postgres driver — no forked backend, just one extra driver and entry point. PostgreSQL is strictly enterprise-only: the community binary has no PostgreSQL dependency and, asked for MAILFOLD_DB_DRIVER=postgres, fails fast with "database driver "postgres" is not available in this build".

Backend

Configuration

The backend is configured entirely through environment variables (see .env.example):

Variable Default Description
MAILFOLD_ADDR :8080 Listen address.
MAILFOLD_MAILCOW_URL — (required) Base URL of the mailcow instance.
MAILFOLD_MAILCOW_API_KEY mailcow API key (X-API-Key).
MAILFOLD_MAILCOW_INSECURE_TLS false Skip TLS verification (dev only).
MAILFOLD_FRONTEND_DIR ./frontend/dist Built SPA directory (optional).

Run

cp .env.example .env   # then edit values
make run               # or: cd backend && go run ./cmd/mailfold

Docker

A prebuilt image is published to Docker Hub:

docker run --rm -p 8080:8080 \
  -e MAILFOLD_MAILCOW_URL=https://mail.example.com \
  -e MAILFOLD_MAILCOW_API_KEY=... \
  -e MAILFOLD_ADMIN_PASSWORD=... \
  sivanov2018/mailfold:0.1.0

Or build it yourself — a multi-stage Dockerfile builds a static binary into a distroless, non-root image:

docker build -t mailfold-backend .
docker run --rm -p 8080:8080 \
  -e MAILFOLD_MAILCOW_URL=https://mail.example.com \
  -e MAILFOLD_MAILCOW_API_KEY=... \
  -e MAILFOLD_ADMIN_PASSWORD=... \
  mailfold-backend

Docker Compose

For local development or simple self-hosting, docker-compose.yml runs the backend and connects it to a mailcow instance (by default a mailcow on the host at :8443):

cp .env.example .env   # set the admin password, mailcow API key, etc.
docker compose up --build

Frontend

The UI is a Vite + React (JSX) single-page app in frontend/: main.jsxApp.jsx (auth gate) → the app shell and pages under src/pages/, talking to the backend through src/api/client.js. The design system is vendored under src/ds/, and all user-facing strings go through the i18n layer in src/i18n/. It builds to frontend/dist/, which the Go backend serves (MAILFOLD_FRONTEND_DIR). See frontend/README.md.

Continuous integration

Every push and pull request runs .github/workflows/ci.yml:

  1. Build & testgo build, go vet, and go test with coverage, failing the run if total coverage drops below 80%.
  2. SonarQube quality gate — analysis is uploaded to SonarQube and the build fails unless the project's quality gate is green.

CI requires two repository settings: a SONAR_TOKEN secret and a SONAR_HOST_URL variable.

License

Mailfold is licensed under the PolyForm Noncommercial License 1.0.0.

You are free to use, modify, and share Mailfold for any noncommercial purpose — personal projects, research, education, nonprofits, and evaluation. Contributions that keep the project growing are welcome. Commercial use is not permitted under this license.

Commercial licenses — including the right to use Mailfold in a paid product or service, or to redistribute it commercially — are available separately from the copyright holder. See mailfold.site.

The official Python, Go, and Rust client SDKs are separate, MIT-licensed projects — they contain no Mailfold server code, only a thin API wrapper, so they're licensed for the widest possible reuse.

Copyright © 2026 Sviatoslav Ivanov (Team26). All rights not expressly granted by the license are reserved.

About

Modern web frontend (admin + webmail) for mailcow — Go backend, React frontend

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors