Files
selfpost/docs/product.md
T
mixandClaude Opus 5.5 30fcf978e0
test / test (push) Waiting to run
docs: clear shipped plans and closed work out of the documents
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>
2026-10-18 22:37:22 +03:00

5.0 KiB

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; install and operations in guide.md; as-built technical detail in 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.


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.

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 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.