release: 1.4.0
test / test (push) Waiting to run

Close Unreleased for inbound relay; pin compose and docs to 1.4.0.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-17 23:20:18 +03:00
parent 0d98d92642
commit d0bf4a4226
8 changed files with 22 additions and 44 deletions
+4 -2
View File
@@ -5,10 +5,12 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version
## [Unreleased] ## [Unreleased]
## [1.4.0] - 2026-08-17
Optional inbound relay (backup-MX / forwarder) on port 25, off by default. Optional inbound relay (backup-MX / forwarder) on port 25, off by default.
Mail is accepted only for domains configured in the panel and forwarded to Mail is accepted only for domains configured in the panel and forwarded to
an upstream; there are still no mailboxes. Security review of the inbound an upstream; there are still no mailboxes. A dedicated security review of
path is pending (Fable). the inbound path is still open on the plan (Fable).
### Added ### Added
+1 -1
View File
@@ -108,7 +108,7 @@ docker run --rm -d --name selfpost-try \
-e SELFPOST_HOSTNAME=mail.local.test \ -e SELFPOST_HOSTNAME=mail.local.test \
-e PANEL_COOKIE_SECURE=false \ -e PANEL_COOKIE_SECURE=false \
-v selfpost-try-data:/data \ -v selfpost-try-data:/data \
ghcr.io/mixeme/selfpost:1.3.1 ghcr.io/mixeme/selfpost:1.4.0
``` ```
**Get the setup URL** (pick one): **Get the setup URL** (pick one):
+1 -1
View File
@@ -22,7 +22,7 @@
services: services:
selfpost: selfpost:
image: ghcr.io/mixeme/selfpost:1.3.1 image: ghcr.io/mixeme/selfpost:1.4.0
restart: unless-stopped restart: unless-stopped
environment: environment:
SELFPOST_HOSTNAME: "${SELFPOST_HOSTNAME:?set the mail/panel hostname, e.g. mail.example.com}" SELFPOST_HOSTNAME: "${SELFPOST_HOSTNAME:?set the mail/panel hostname, e.g. mail.example.com}"
+1 -1
View File
@@ -102,7 +102,7 @@ than the default «meaningful step» rule in [§ Commits and release build](#com
2. Git tag `vX.Y.Z` and publish the GitHub Release only on explicit request (see 2. Git tag `vX.Y.Z` and publish the GitHub Release only on explicit request (see
[§ Release image](#release-image)). [§ Release image](#release-image)).
**Planned version cuts** (from pin `1.3.1`; adjust if semver changes mid-track): **Planned version cuts** (from pin `1.4.0`; adjust if semver changes mid-track):
| Stage | ID | Cut | | Stage | ID | Cut |
|---|---|---| |---|---|---|
+2 -2
View File
@@ -169,7 +169,7 @@ cat ./data/setup-token
#### Fixed image tag #### Fixed image tag
`deploy/docker-compose.yml` pins an explicit version (`ghcr.io/mixeme/selfpost:X.Y.Z`), `deploy/docker-compose.yml` pins an explicit version (`ghcr.io/mixeme/selfpost:X.Y.Z`),
deliberately never `:latest`. The current pin is `1.3.1`. Intermediate deliberately never `:latest`. The current pin is `1.4.0`. Intermediate
CHANGELOG sections (`0.2.0``0.6.0`) record development cuts from before that CHANGELOG sections (`0.2.0``0.6.0`) record development cuts from before that
image was published. Pinning matters because of the backup version check (see image was published. Pinning matters because of the backup version check (see
[Full backup and restore](#full-backup-and-restore)): the panel binary's [Full backup and restore](#full-backup-and-restore)): the panel binary's
@@ -489,7 +489,7 @@ A version mismatch at step 5 refuses to start and leaves `/data` untouched —
the panel exits with a message naming the tag to use, e.g.: the panel exits with a message naming the tag to use, e.g.:
``` ```
backup: this backup was created by SelfPost 1.2.3 but this image is 1.3.1 — restore into the matching image (selfpost:1.2.3) backup: this backup was created by SelfPost 1.2.3 but this image is 1.4.0 — restore into the matching image (selfpost:1.2.3)
``` ```
Fix the tag in `docker-compose.yml`, `docker compose pull && docker compose up Fix the tag in `docker-compose.yml`, `docker compose pull && docker compose up
+4 -7
View File
@@ -1,12 +1,9 @@
# Plan: inbound-relay (inbound relay) # Plan: inbound-relay (inbound relay)
**Status:** agreed **Status:** done — shipped in `[1.4.0]` (2026-08-17)
**Version:** target bump **1.x** MINOR; **`2.x` possible** — to be settled once **Version:** 1.4.0 MINOR (flag off is compatible; not a 2.x break).
the implementation lands (do not fix a major in advance). **Order:** after queue-retries `[1.3.1]`. One checklist step remains:
**Order:** queue-retries shipped in `[1.3.1]`; this is next as the largest security review of the inbound path (Fable).
remaining 1.x+ **feature**. The 2026-08-13 full-tree review follow-ups closed
in `[1.3.0]`. The domain-admin role and `internal/web` split have shipped —
see [CHANGELOG](../../CHANGELOG.md) `[1.2.0]`.
--- ---
+2 -2
View File
@@ -57,8 +57,8 @@ Explicitly excluded to prevent scope creep:
The **domain-admin** role ships in the current line (global administrator plus The **domain-admin** role ships in the current line (global administrator plus
domain administrators with assigned domains). The optional **inbound relay** domain administrators with assigned domains). The optional **inbound relay**
(backup-MX / forwarder on port 25) is an agreed 1.x extension — off by default (backup-MX / forwarder on port 25) ships in `[1.4.0]`, off by default behind
behind `INBOUND_RELAY_ENABLE`; it is relay/forward, not IMAP/webmail. Items `INBOUND_RELAY_ENABLE`; it is relay/forward, not IMAP/webmail. Items
marked *candidate* in the marked *candidate* in the
[roadmap](roadmap.md) require explicit approval before coding (including [roadmap](roadmap.md) require explicit approval before coding (including
**send-log retention in Settings**, **30-day send statistics**, and **auto **send-log retention in Settings**, **30-day send statistics**, and **auto
+7 -28
View File
@@ -28,7 +28,6 @@ in `git log` and [CHANGELOG.md](../CHANGELOG.md).
| ID | Topic | Status | Progress | Plan | | ID | Topic | Status | Progress | Plan |
|---|---|---|---|---| |---|---|---|---|---|
| inbound-relay | Inbound relay (backup-MX / forwarding) | **agreed** | 14/15 | [plans/inbound-relay.md](plans/inbound-relay.md) |
| send-log-retention | Send-log retention days in panel Settings | candidate | 0/8 | [plans/send-log-retention.md](plans/send-log-retention.md) | | send-log-retention | Send-log retention days in panel Settings | candidate | 0/8 | [plans/send-log-retention.md](plans/send-log-retention.md) |
| domain-stats-auto-ratelimit | 30-day send stats + auto level-2 rate limit | candidate | 0/11 | [plans/domain-stats-auto-ratelimit.md](plans/domain-stats-auto-ratelimit.md) | | domain-stats-auto-ratelimit | 30-day send stats + auto level-2 rate limit | candidate | 0/11 | [plans/domain-stats-auto-ratelimit.md](plans/domain-stats-auto-ratelimit.md) |
| contributing | `CONTRIBUTING.md` | candidate | — | — | | contributing | `CONTRIBUTING.md` | candidate | — | — |
@@ -36,12 +35,13 @@ in `git log` and [CHANGELOG.md](../CHANGELOG.md).
| panel-docs | In-panel operator documentation | candidate | 0/6 | [plans/panel-docs.md](plans/panel-docs.md) | | panel-docs | In-panel operator documentation | candidate | 0/6 | [plans/panel-docs.md](plans/panel-docs.md) |
| schema-squash | Squash SQLite migrations into a 2.x baseline | **2.x** | — | — | | schema-squash | Squash SQLite migrations into a 2.x baseline | **2.x** | — | — |
**Recommended order** (not binding): the next feature is **inbound-relay**. **Recommended order** (not binding): the next feature is
**send-log-retention** can land before or beside **domain-stats-auto-ratelimit** **send-log-retention** once agreed. It can land before or beside
(panel retention ≥ 30 days helps the stats window). queue-retries shipped in **domain-stats-auto-ratelimit** (panel retention ≥ 30 days helps the stats
[CHANGELOG.md](../CHANGELOG.md) `[1.3.1]`; the 2026-08-13 full-tree review window). inbound-relay shipped in
follow-ups are in `[1.3.0]`. Candidates need explicit agreement before they [CHANGELOG.md](../CHANGELOG.md) `[1.4.0]`; queue-retries in `[1.3.1]`; the
join the queue. 2026-08-13 full-tree review follow-ups are in `[1.3.0]`. Candidates need
explicit agreement before they join the queue.
After a context reset, pick an item marked `agreed` or `in progress`, then work After a context reset, pick an item marked `agreed` or `in progress`, then work
the **Implementation checklist** in its linked plan. The `Progress` column above the **Implementation checklist** in its linked plan. The `Progress` column above
@@ -50,27 +50,6 @@ is `done/total` checklist steps in that plan ([development.md](development.md)
--- ---
## inbound-relay
**Goal:** optional acceptance of mail on port 25 for explicitly configured
domains, forwarded to an upstream (backup-MX / relay-forwarder). Off by default
(`INBOUND_RELAY_ENABLE=false`); without the flag the outbound path is
unchanged.
**Boundary:** an extension of v1.0 — [product.md](product.md) excludes inbound
mail and mailboxes. This is relay/forward, not IMAP/POP3/webmail; an anti-spam
engine stays outside the image, only the attachment point is provided.
**Done when:** see the criteria in
[plans/inbound-relay.md](plans/inbound-relay.md).
**Dependencies / risks:** a finished outbound path; open relay and backscatter;
a wider attack surface (port 25 accepting mail).
**Version:** target bump `1.x`; `2.x` possible — to be settled once the
implementation lands.
---
## send-log-retention ## send-log-retention
**Goal:** global administrator sets how many days of delivery journal rows **Goal:** global administrator sets how many days of delivery journal rows