test / test (push) Waiting to run
Owner, 2026-10-18: "Надо почистить документы от устаревшего и сделанного." - Deleted, shipped: plans/delivery-log-storage, from-header-binding, inbound-antispam-panel, inbound-upstream-result, panel-dkim-signing, panel-notifications, and the own-mta-builds analysis (its three rows shipped as 2.6.1, 2.7.0, 2.8.0). What outlived them moved first: when a filter-list counter is worth a migration, and the notifications' "when" table, into architecture.md; the sender check's own-process trigger into security.md. Code comments that cited them point at architecture.md or security.md; CHANGELOG keeps their names, unlinked. - Kept, marked closed: audit-2026-10-12, assumptions-2026-10-14 and security-audit-2026-10-17 - the code cites their finding ids in 50-84 files. Their file:line refs are of the tree each audited. - roadmap.md: open work only - stage H of the security audit (the owner's), go-milter-upstream (the owner posts), and queue-table, which the redesign left undecided and only its own shipped section still named; Dropped and Ideas as they were. 2.x versioning instead of 1.x. - development.md: the 47-row planned-version-cuts table (history, in the CHANGELOG) gone; a stage's last step now removes its roadmap item and plan. Docs map lists the closed audits. - panel-redesign.md: the done checklist out; Room for roadmap items says which drawn screens are unbuilt and why. - Stale facts fixed: schema-migrations.md and architecture.md at schema 14 (0013's users columns and user_links, 0014's secure TLS mode); security.md's accepted risk "profile saved without the password" - the e-mail asks for it since 2.14.0. Tests: go build, go vet; go test of cmd and the touched internal packages pass except logtail's three Windows-bound rotation tests (rename of an open file; CI is Linux). Only comments changed in Go. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
127 lines
5.0 KiB
Markdown
127 lines
5.0 KiB
Markdown
# SelfPost — product boundaries
|
|
|
|
**What this file is.** Stable product definition of SelfPost: purpose,
|
|
deployment assumptions, explicit out-of-scope items, and the multi-domain
|
|
model. User-facing overview in [README.md](../README.md); install and operations
|
|
in [guide.md](guide.md); as-built technical detail in
|
|
[architecture.md](architecture.md).
|
|
|
|
---
|
|
|
|
## Purpose
|
|
|
|
SelfPost is a self-hosted **SMTP relay** with a web control panel, shipped as a
|
|
single Docker image. It sends mail directly from your server with per-domain
|
|
DKIM signing; an optional inbound relay forwards mail on port 25 without
|
|
storing it.
|
|
|
|
**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.
|
|
|
|
## Positioning
|
|
|
|
| | Text |
|
|
|---|---|
|
|
| Stamp subtitle | SELF-HOSTED SMTP RELAY |
|
|
| Wordmark | The stamp's own letter outlines without the stamp (`docs/assets/selfpost-wordmark.svg`, `-ink` for light grounds) — for places too small for the stamp, such as the panel header |
|
|
| Tagline | YOUR SMTP. YOUR RULES. |
|
|
| Hero line (README, GitHub) | Self-hosted SMTP relay with a web panel — one Docker image, no provider. |
|
|
|
|
Brand assets and metrics: [docs/assets/selfpost-proof.html](assets/selfpost-proof.html).
|
|
|
|
---
|
|
|
|
## Deployment context (fixed assumptions)
|
|
|
|
These constraints are intentional; changing them requires an explicit product
|
|
decision:
|
|
|
|
1. **VPS or home server** — one image for both. Raspberry Pi and similar boards
|
|
are not a current target but not ruled out forever.
|
|
2. **Send from your own IP (DIY)** — no intermediate relay provider. Requires
|
|
outbound port 25, static IP, and configurable PTR/rDNS from the operator.
|
|
3. **Single container** — Postfix and the panel, which signs outgoing mail
|
|
with DKIM itself, run under one `supervisord` inside one image.
|
|
4. **Panel is internet-facing** — mandatory security requirements in
|
|
[security.md](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
|
|
- Organisations / tenancy beyond the `global` and `domain` roles; managing
|
|
**multiple sending domains** under one global administrator is in scope (see
|
|
below)
|
|
- Inbound antispam/antivirus engines (rspamd, ClamAV, etc.) — the image
|
|
ships no filter, only a milter hook; `deploy/antispam` offers an optional
|
|
rspamd sidecar that the panel's filter lists feed
|
|
- A custom MTA — Postfix is used as-is
|
|
- Dovecot or a full mail stack for SASL — Cyrus SASL (`sasldb2`) only
|
|
|
|
The **`domain`** role ships in the current line (a `global` user plus
|
|
`domain` users with assigned domains, outbound and inbound separately). The
|
|
optional **inbound relay** (backup-MX / forwarder on port 25) ships in `[1.4.0]`, off by default behind
|
|
`INBOUND_RELAY_ENABLE`; it is relay/forward, not IMAP/webmail. **Send-log
|
|
retention in Settings** ships in `[1.5.0]`. **30-day send statistics** and
|
|
**auto level-2 rate limits** ship in `[1.6.0]`. **DMARC aggregate report
|
|
ingest** ships in `[1.7.0]`, off by default behind `DMARC_REPORTS_ENABLE`.
|
|
Items marked *candidate* in the
|
|
[roadmap](roadmap.md) require explicit approval before coding.
|
|
|
|
---
|
|
|
|
## 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:
|
|
|
|
1. **Any address in the domain** — `*@example.com` (wildcard in
|
|
`smtpd_sender_login_maps`).
|
|
2. **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; it is one owner (or a small team with global and
|
|
domain-scoped roles) operating several sending domains with independent
|
|
application credentials.
|