A bounce could be recorded as a successful delivery. The log-tailer's Fixed: - A bounce could be recorded as a successful delivery. The log-tailer's - Log-tailer resumes where it stopped instead of jumping to end-of-file on - Level-2 rate limit no longer overshoots under concurrency: messages that Changed: - The project has a single public home: `github.com/mixeme/selfpost`. Codeberg - Code comments no longer cite the archived specification. References like - `docs/code-review.md` is gone. Its plan is finished — phases 0 (bar the - `docs/architecture.md` gained a *Code layers* section: a diagram of - Phase 1 doc/code hygiene (`docs/code-review.md`): removed ~30 stale … (1 more in CHANGELOG) Security: - Pre-release security review (plan § D, model Fable, 2026-08-06): full pass - `saslpasswd2` argv: the application login is now passed after a `--` Added: - Optional password encryption for the two secret-bearing downloads (plan - Domain import accepts an encrypted export: the envelope is detected by its - `selfpost-backup` writes encrypted archives and reads them back: - `TestParseDelivery` covers the exotic mail.log shapes the review asked for - docs: README *Encrypting a backup or export*; `docs/security.md` § … (14 more in CHANGELOG) Removed: - docs: `security.md` — accepted risk «restore old backup revives session rows» Changed: - docs: `implementation-plan.md` trimmed to the sole open v1.x gate — pre-release - docs: `architecture.md` — sessions (SQLite, idle renew, password change), - docs: `development.md` — expanded e2e stack and `release.yml` matrix workflow. - docs: `security.md` — accepted risk for send-log rows stuck at `queued` after - docs: `roadmap.md` — optional send-log / `mail.log` follow-ups under v1.x tail. … (10 more in CHANGELOG) Full detail: CHANGELOG.md (0.5.0).
3.7 KiB
SelfPost — product boundaries
What this file is. Stable product definition for SelfPost v1.0: purpose, deployment assumptions, explicit out-of-scope items, and the multi-domain model. User-facing install and operations live in README.md; as-built technical detail in architecture.md.
Purpose
SelfPost is a self-hosted outbound SMTP relay with a web control panel, shipped as a single Docker image. It sends mail directly to the internet from your own IP with per-domain DKIM signing.
Primary workflow: configure the relay once (domains, DKIM, SASL applications), then point scripts and apps at the SMTP endpoint. SelfPost delivers as the configured sending domain.
Deployment context (fixed assumptions)
These constraints are intentional; changing them requires an explicit product decision:
- VPS or home server — one image for both. Raspberry Pi and similar boards are not a current target but not ruled out forever.
- Send from your own IP (DIY) — no intermediate relay provider. Requires outbound port 25, static IP, and configurable PTR/rDNS from the operator.
- Single container — Postfix, OpenDKIM, and the panel run under one
supervisordinside one image. - Panel is internet-facing — mandatory security requirements in security.md.
Infrastructure the operator provides (not SelfPost features): unblocked outbound TCP 25, static IP, PTR/rDNS, acceptable IP reputation. SelfPost does not detect, bypass, or compensate for missing prerequisites; mail simply fails to deliver when they are absent.
Out of scope
Explicitly excluded to prevent scope creep:
- Inbound mail (IMAP/POP3, mailboxes, delivery to user inboxes)
- Webmail
- Multi-user panel / organisations / roles — one administrator; managing multiple sending domains is in scope (see below)
- Inbound antispam/antivirus (rspamd, ClamAV, etc.)
- A custom MTA — Postfix is used as-is
- Dovecot or a full mail stack for SASL — Cyrus SASL (
sasldb2) only
Future line 2.x.x (optional inbound relay, domain-admin role) is tracked in roadmap.md and requires explicit approval before implementation.
Multi-domain model
SelfPost is a multi-domain outbound relay. Two linked entities:
Sending domain
Example: example.com. Has its own DKIM key and selector.
Application (account)
A SASL login/password bound to one domain. A domain may have several applications (e.g. newsletter vs alerts), each with its own credentials, but each may send only from its own domain, never from another.
From-address mode (per application)
Set when creating or editing an application:
- Any address in the domain —
*@example.com(wildcard insmtpd_sender_login_maps). - Explicit address list — only listed From addresses within the domain; anything else is rejected even if it belongs to the same domain.
In both modes the From address must belong to the application's domain.
What the panel manages per domain
- DKIM key + selector (shared by all applications on that domain)
- One or more applications (SASL credentials + From mode + optional rate limits)
- DNS guidance (DKIM TXT; reminders for SPF/DMARC)
Adding a domain does not create an application automatically.
Lifecycle
- Add domain — record, DKIM key, DNS instructions; no application yet.
- Add application — SASL pair (password shown once), From mode, map entries,
postfix reload. - Delete domain — removes DKIM key and all its applications.
- Delete application — removes only that app's SASL and map entries.
This is not multi-tenancy (one admin); it is one owner operating several sending domains with independent application credentials.