xListman - A one-binary, self-hosted mailing list manager. A self-contained alternative to GNU Mailman.
2
stars
51
commits
Go
primary language
Aug 21, 2026
updated
A one-binary, self-hosted mailing list manager. A modern, self-contained alternative to GNU Mailman: manage mailing lists, subscriptions, archives, and moderation from a passwordless web UI and a CLI, delivered as a single static binary with an embedded frontend and SQLite storage.
Mailing lists
subscribe, confirm, post, unsubscribe,
bounce handling, and -request commands (which, set digest, …) — all by
writing to listname+role@domainModeration & roles
Delivery
Web UI
Operations
xlistman domain|list|owner|subscriber|…${ENV_VAR} secret expansionsystemd unit and a multi-stage scratch-based Docker image includedCaptured from a live instance seeded with demo data — reproduce them with
scripts/screenshot-seed.sh. Click a thumbnail to open it full size.
docker run -d --name xlistman \
-p 8080:8080 -p 8024:8024 \
-v xlistman-data:/data \
-e XLISTMAN_WEB_BASE_URL=http://localhost:8080 \
ghcr.io/barats/xlistman:0.2.0
The image ships a working default config (/etc/xlistman/config.yaml); any
value can be overridden with XLISTMAN_* environment variables (e.g. point
XLISTMAN_SMTP_HOST / XLISTMAN_SMTP_PORT at your relay). See
Configuration.
Prerequisites: Go 1.25+, and Node.js + pnpm for the embedded web UI.
cd web && pnpm install && pnpm build # build the SvelteKit frontend
cd .. && go build -o xlistman . # then the Go binary (UI embedded)
./xlistman config init # generate ./xlistman.yaml, then edit it
./xlistman serve
The web UI is generated and not committed, so
go install github.com/barats/xlistman@latest(and a plaingo build) produces a binary without the web UI — CLI and mail handling only. For the full product, use the Docker image (above) or download a release binary from the GitHub Releases page, which ships the frontend embedded (goreleaser builds it as part of the release).
# create a domain, then a list with its first owner
xlistman domain add example.com "Example domain"
xlistman list create dev@example.com --type discussion --owner you@example.com
xlistman serve # start the daemon (HTTP :8080, LMTP :8024, pipe socket)
Open http://localhost:8080, request a login link, and you're in. To receive
mail, wire your MTA to deliver the list domain over LMTP (see below).
xListman integrates with an existing mail server rather than replacing it. The flow: your MTA accepts mail for the list domain and hands it to xListman over LMTP (or the pipe-mode Unix socket); xListman delivers outbound mail back through your relay.
virtual_mailbox_domains = lists.example.com +
virtual_transport = lmtp:[127.0.0.1]:8024manualroute router sending the list domain to an smtp
transport with protocol = lmtp on 127.0.0.1:8024Both configurations are exercised end-to-end against live local instances,
including the VERP bounce reverse leg. The reproducible harnesses live in
validate/.
Configuration is YAML, loaded from xlistman.yaml (or XLISTMAN_CONFIG),
overlaid with XLISTMAN_* environment variables, and expanded for ${ENV_VAR}
secrets. A minimal runnable config ships as
config.default.yaml; generate a fully commented one
with xlistman config init.
| Area | Key settings |
|---|---|
| HTTP / LMTP / socket | http.listen, lmtp.listen, socket.path |
| Storage | database.path |
| Outbound | smtp.host, smtp.port, smtp.username/password, smtp.mode (smtp|sink), smtp.sink_dir, smtp.tls (none|starttls|starttls-required|implicit), smtp.tls_insecure_skip_verify |
| Web | web.base_url (public origin used in emails), web.site_name (instance name in titles and the UI) |
| Protection | rate_limits.* (subscribe / magic-link / posts per hour) |
| Delivery | queue.max_retries |
See internal/config/config.go for the full list
of environment variable names.
CONTEXT.md — the domain model and glossary (Subscriber,
Subscription, List Role, Held Message, …)docs/PLAN.md — build history and roadmapdocs/adr/ — 26 architecture decision recordsvalidate/README.md — MTA validation harnessesSECURITY.md — security policy and reportingActive, pre-1.0. Versioned with semantic versioning; 0.x indicates the
storage/config surface may still evolve. See the Next section in
docs/PLAN.md for the roadmap.
MIT © 2026 Barat Semet
51 commits
Go
76.1%
Svelte
16.3%
TypeScript
4.2%
Shell
2.8%
xListman - A one-binary, self-hosted mailing list manager. A self-contained alternative to GNU Mailman.
2
stars
51
commits
Go
primary language
Aug 21, 2026
updated
A one-binary, self-hosted mailing list manager. A modern, self-contained alternative to GNU Mailman: manage mailing lists, subscriptions, archives, and moderation from a passwordless web UI and a CLI, delivered as a single static binary with an embedded frontend and SQLite storage.
Mailing lists
subscribe, confirm, post, unsubscribe,
bounce handling, and -request commands (which, set digest, …) — all by
writing to listname+role@domainModeration & roles
Delivery
Web UI
Operations
xlistman domain|list|owner|subscriber|…${ENV_VAR} secret expansionsystemd unit and a multi-stage scratch-based Docker image includedCaptured from a live instance seeded with demo data — reproduce them with
scripts/screenshot-seed.sh. Click a thumbnail to open it full size.
docker run -d --name xlistman \
-p 8080:8080 -p 8024:8024 \
-v xlistman-data:/data \
-e XLISTMAN_WEB_BASE_URL=http://localhost:8080 \
ghcr.io/barats/xlistman:0.2.0
The image ships a working default config (/etc/xlistman/config.yaml); any
value can be overridden with XLISTMAN_* environment variables (e.g. point
XLISTMAN_SMTP_HOST / XLISTMAN_SMTP_PORT at your relay). See
Configuration.
Prerequisites: Go 1.25+, and Node.js + pnpm for the embedded web UI.
cd web && pnpm install && pnpm build # build the SvelteKit frontend
cd .. && go build -o xlistman . # then the Go binary (UI embedded)
./xlistman config init # generate ./xlistman.yaml, then edit it
./xlistman serve
The web UI is generated and not committed, so
go install github.com/barats/xlistman@latest(and a plaingo build) produces a binary without the web UI — CLI and mail handling only. For the full product, use the Docker image (above) or download a release binary from the GitHub Releases page, which ships the frontend embedded (goreleaser builds it as part of the release).
# create a domain, then a list with its first owner
xlistman domain add example.com "Example domain"
xlistman list create dev@example.com --type discussion --owner you@example.com
xlistman serve # start the daemon (HTTP :8080, LMTP :8024, pipe socket)
Open http://localhost:8080, request a login link, and you're in. To receive
mail, wire your MTA to deliver the list domain over LMTP (see below).
xListman integrates with an existing mail server rather than replacing it. The flow: your MTA accepts mail for the list domain and hands it to xListman over LMTP (or the pipe-mode Unix socket); xListman delivers outbound mail back through your relay.
virtual_mailbox_domains = lists.example.com +
virtual_transport = lmtp:[127.0.0.1]:8024manualroute router sending the list domain to an smtp
transport with protocol = lmtp on 127.0.0.1:8024Both configurations are exercised end-to-end against live local instances,
including the VERP bounce reverse leg. The reproducible harnesses live in
validate/.
Configuration is YAML, loaded from xlistman.yaml (or XLISTMAN_CONFIG),
overlaid with XLISTMAN_* environment variables, and expanded for ${ENV_VAR}
secrets. A minimal runnable config ships as
config.default.yaml; generate a fully commented one
with xlistman config init.
| Area | Key settings |
|---|---|
| HTTP / LMTP / socket | http.listen, lmtp.listen, socket.path |
| Storage | database.path |
| Outbound | smtp.host, smtp.port, smtp.username/password, smtp.mode (smtp|sink), smtp.sink_dir, smtp.tls (none|starttls|starttls-required|implicit), smtp.tls_insecure_skip_verify |
| Web | web.base_url (public origin used in emails), web.site_name (instance name in titles and the UI) |
| Protection | rate_limits.* (subscribe / magic-link / posts per hour) |
| Delivery | queue.max_retries |
See internal/config/config.go for the full list
of environment variable names.
CONTEXT.md — the domain model and glossary (Subscriber,
Subscription, List Role, Held Message, …)docs/PLAN.md — build history and roadmapdocs/adr/ — 26 architecture decision recordsvalidate/README.md — MTA validation harnessesSECURITY.md — security policy and reportingActive, pre-1.0. Versioned with semantic versioning; 0.x indicates the
storage/config surface may still evolve. See the Next section in
docs/PLAN.md for the roadmap.
MIT © 2026 Barat Semet
51 commits
Go
76.1%
Svelte
16.3%
TypeScript
4.2%
Shell
2.8%