Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a51db277b | ||
|
|
6adbb41459 |
+18
-9
@@ -5,6 +5,12 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [1.9.1] - 2026-08-19
|
||||||
|
|
||||||
|
Port-25 Postfix startup when inbound relay, DMARC ingest, or the inbound antispam
|
||||||
|
milter are enabled. Schema-migration reference and roadmap plans for inbound
|
||||||
|
antispam and quarantine. Upgrading from 1.9.0 is a tag bump; no migration.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- [docs/plans/inbound-antispam-panel.md](docs/plans/inbound-antispam-panel.md) —
|
- [docs/plans/inbound-antispam-panel.md](docs/plans/inbound-antispam-panel.md) —
|
||||||
@@ -13,6 +19,9 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version
|
|||||||
`1.10.0`; Composer → Opus → Fable workflow.
|
`1.10.0`; Composer → Opus → Fable workflow.
|
||||||
- [docs/plans/inbound-quarantine.md](docs/plans/inbound-quarantine.md) — candidate
|
- [docs/plans/inbound-quarantine.md](docs/plans/inbound-quarantine.md) — candidate
|
||||||
plan for held-mail review/release (design TBD).
|
plan for held-mail review/release (design TBD).
|
||||||
|
- [docs/schema-migrations.md](docs/schema-migrations.md) — living reference for the
|
||||||
|
SQLite migration chain (`user_version` head, per-file history, legacy artefacts,
|
||||||
|
1.x rules, and planned 2.x squash gate).
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
@@ -20,19 +29,19 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version
|
|||||||
and `inbound-quarantine` (candidate) in the index.
|
and `inbound-quarantine` (candidate) in the index.
|
||||||
- [docs/development.md](docs/development.md) — plan checklists may override
|
- [docs/development.md](docs/development.md) — plan checklists may override
|
||||||
model routing with Composer → Opus → Fable.
|
model routing with Composer → Opus → Fable.
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
- [docs/schema-migrations.md](docs/schema-migrations.md) — living reference for the
|
|
||||||
SQLite migration chain (`user_version` head, per-file history, legacy artefacts,
|
|
||||||
1.x rules, and planned 2.x squash gate).
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
- [docs/development.md](docs/development.md), [docs/roadmap.md](docs/roadmap.md),
|
- [docs/development.md](docs/development.md), [docs/roadmap.md](docs/roadmap.md),
|
||||||
and [docs/architecture.md](docs/architecture.md) link to the new file;
|
and [docs/architecture.md](docs/architecture.md) link to the new file;
|
||||||
`schema-squash` defers gate thresholds to it instead of a stale v5 snapshot.
|
`schema-squash` defers gate thresholds to it instead of a stale v5 snapshot.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- `build/postfix-config.sh`: enabling inbound relay, DMARC ingest, and/or the
|
||||||
|
inbound antispam milter no longer crash-loops on start — `postconf -P` cannot
|
||||||
|
set `master.cf` `-o` values that contain whitespace, so port-25
|
||||||
|
`smtpd_recipient_restrictions` and `smtpd_milters` are patched directly; DMARC
|
||||||
|
pipe `argv` uses a `dmarc-ingest` symlink instead of `panel -dmarc-ingest`.
|
||||||
|
|
||||||
|
## [1.9.0] - 2026-08-18
|
||||||
|
|
||||||
Application sending controls: client IP allow-list for authorization, and
|
Application sending controls: client IP allow-list for authorization, and
|
||||||
level-2 rate limits that override the domain ceiling per application.
|
level-2 rate limits that override the domain ceiling per application.
|
||||||
|
|||||||
+40
-6
@@ -13,6 +13,37 @@
|
|||||||
# a fixed literal or a container environment variable (spec 7.6.3).
|
# a fixed literal or a container environment variable (spec 7.6.3).
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
|
# postconf -P refuses master.cf -o values that contain whitespace; inbound port
|
||||||
|
# 25 needs restriction lists and milter specs that include spaces. Patch the
|
||||||
|
# smtp/inet service stanza directly instead.
|
||||||
|
master_cf_set_smtp_inet_o() {
|
||||||
|
param="$1"
|
||||||
|
value="$2"
|
||||||
|
awk -v p="$param" -v v="$value" '
|
||||||
|
/^smtp[ \t]+inet[ \t]/ && !done {
|
||||||
|
print
|
||||||
|
print " -o " p "=" v
|
||||||
|
done = 1
|
||||||
|
in_smtp_inet = 1
|
||||||
|
next
|
||||||
|
}
|
||||||
|
in_smtp_inet && /^[ \t]+-o / {
|
||||||
|
line = $0
|
||||||
|
sub(/^[ \t]+-o /, "", line)
|
||||||
|
eq = index(line, "=")
|
||||||
|
on = substr(line, 1, eq - 1)
|
||||||
|
if (on == p) {
|
||||||
|
next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
in_smtp_inet && /^[^ \t#-]/ {
|
||||||
|
in_smtp_inet = 0
|
||||||
|
}
|
||||||
|
{ print }
|
||||||
|
' /etc/postfix/master.cf > /etc/postfix/master.cf.new
|
||||||
|
mv /etc/postfix/master.cf.new /etc/postfix/master.cf
|
||||||
|
}
|
||||||
|
|
||||||
# --- environment knobs (spec 8) ----------------------------------------------
|
# --- environment knobs (spec 8) ----------------------------------------------
|
||||||
# Server hostname: used as HELO name AND, crucially, as the Cyrus SASL realm the
|
# Server hostname: used as HELO name AND, crucially, as the Cyrus SASL realm the
|
||||||
# sasldb2 accounts are looked up under. The panel creates accounts under realm
|
# sasldb2 accounts are looked up under. The panel creates accounts under realm
|
||||||
@@ -235,17 +266,18 @@ if [ "${INBOUND_RELAY_ENABLE}" = "true" ] || [ "${DMARC_REPORTS_ENABLE}" = "true
|
|||||||
done
|
done
|
||||||
RELAY_DOMAINS_SETTING="texthash:${RELAY_DOMAINS_MAP}"
|
RELAY_DOMAINS_SETTING="texthash:${RELAY_DOMAINS_MAP}"
|
||||||
TRANSPORT_SETTING="texthash:${TRANSPORT_MAP}"
|
TRANSPORT_SETTING="texthash:${TRANSPORT_MAP}"
|
||||||
RECIPIENT_RESTRICTIONS="reject_unauth_destination, reject_unlisted_recipient"
|
RECIPIENT_RESTRICTIONS="reject_unauth_destination,reject_unlisted_recipient"
|
||||||
fi
|
fi
|
||||||
if [ "${DMARC_REPORTS_ENABLE}" = "true" ]; then
|
if [ "${DMARC_REPORTS_ENABLE}" = "true" ]; then
|
||||||
for f in "$DMARC_RECIPIENTS_MAP" "$DMARC_TRANSPORT_MAP" "$DMARC_RELAY_DOMAINS_MAP"; do
|
for f in "$DMARC_RECIPIENTS_MAP" "$DMARC_TRANSPORT_MAP" "$DMARC_RELAY_DOMAINS_MAP"; do
|
||||||
[ -e "$f" ] || : > "$f"
|
[ -e "$f" ] || : > "$f"
|
||||||
done
|
done
|
||||||
|
ln -sf /usr/local/bin/panel /usr/local/bin/dmarc-ingest
|
||||||
postconf -M "dmarc-ingest/unix-pipe=dmarc-ingest unix - n n - - pipe"
|
postconf -M "dmarc-ingest/unix-pipe=dmarc-ingest unix - n n - - pipe"
|
||||||
postconf -P \
|
postconf -P \
|
||||||
"dmarc-ingest/unix-pipe/flags=Rq" \
|
"dmarc-ingest/unix-pipe/flags=Rq" \
|
||||||
"dmarc-ingest/unix-pipe/user=panel" \
|
"dmarc-ingest/unix-pipe/user=panel" \
|
||||||
"dmarc-ingest/unix-pipe/argv=/usr/local/bin/panel -dmarc-ingest"
|
"dmarc-ingest/unix-pipe/argv=/usr/local/bin/dmarc-ingest"
|
||||||
if [ -n "$RELAY_DOMAINS_SETTING" ]; then
|
if [ -n "$RELAY_DOMAINS_SETTING" ]; then
|
||||||
RELAY_DOMAINS_SETTING="${RELAY_DOMAINS_SETTING} texthash:${DMARC_RELAY_DOMAINS_MAP}"
|
RELAY_DOMAINS_SETTING="${RELAY_DOMAINS_SETTING} texthash:${DMARC_RELAY_DOMAINS_MAP}"
|
||||||
TRANSPORT_SETTING="${TRANSPORT_SETTING} texthash:${DMARC_TRANSPORT_MAP}"
|
TRANSPORT_SETTING="${TRANSPORT_SETTING} texthash:${DMARC_TRANSPORT_MAP}"
|
||||||
@@ -253,7 +285,7 @@ if [ "${INBOUND_RELAY_ENABLE}" = "true" ] || [ "${DMARC_REPORTS_ENABLE}" = "true
|
|||||||
RELAY_DOMAINS_SETTING="texthash:${DMARC_RELAY_DOMAINS_MAP}"
|
RELAY_DOMAINS_SETTING="texthash:${DMARC_RELAY_DOMAINS_MAP}"
|
||||||
TRANSPORT_SETTING="texthash:${DMARC_TRANSPORT_MAP}"
|
TRANSPORT_SETTING="texthash:${DMARC_TRANSPORT_MAP}"
|
||||||
fi
|
fi
|
||||||
RECIPIENT_RESTRICTIONS="check_recipient_access texthash:${DMARC_RECIPIENTS_MAP}, ${RECIPIENT_RESTRICTIONS}"
|
RECIPIENT_RESTRICTIONS="check_recipient_access texthash:${DMARC_RECIPIENTS_MAP},${RECIPIENT_RESTRICTIONS}"
|
||||||
fi
|
fi
|
||||||
postconf -e \
|
postconf -e \
|
||||||
"relay_domains=${RELAY_DOMAINS_SETTING}" \
|
"relay_domains=${RELAY_DOMAINS_SETTING}" \
|
||||||
@@ -285,7 +317,7 @@ if [ "${INBOUND_RELAY_ENABLE}" = "true" ] || [ "${DMARC_REPORTS_ENABLE}" = "true
|
|||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
INBOUND_MILTERS="{ ${INBOUND_ANTISPAM_MILTER}, default_action=${INBOUND_ANTISPAM_MILTER_ACTION} }"
|
INBOUND_MILTERS="{${INBOUND_ANTISPAM_MILTER},default_action=${INBOUND_ANTISPAM_MILTER_ACTION}}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
PORT25_RATE="${INBOUND_RATE_LIMIT_MESSAGES_PER_IP}"
|
PORT25_RATE="${INBOUND_RATE_LIMIT_MESSAGES_PER_IP}"
|
||||||
@@ -311,10 +343,12 @@ if [ "${INBOUND_RELAY_ENABLE}" = "true" ] || [ "${DMARC_REPORTS_ENABLE}" = "true
|
|||||||
"smtp/inet/smtpd_sender_restrictions=" \
|
"smtp/inet/smtpd_sender_restrictions=" \
|
||||||
"smtp/inet/smtpd_client_restrictions=" \
|
"smtp/inet/smtpd_client_restrictions=" \
|
||||||
"smtp/inet/smtpd_relay_restrictions=reject_unauth_destination" \
|
"smtp/inet/smtpd_relay_restrictions=reject_unauth_destination" \
|
||||||
"smtp/inet/smtpd_recipient_restrictions=${RECIPIENT_RESTRICTIONS}" \
|
|
||||||
"smtp/inet/smtpd_milters=${INBOUND_MILTERS}" \
|
|
||||||
"smtp/inet/smtpd_client_message_rate_limit=${PORT25_RATE}" \
|
"smtp/inet/smtpd_client_message_rate_limit=${PORT25_RATE}" \
|
||||||
"smtp/inet/message_size_limit=${PORT25_SIZE}"
|
"smtp/inet/message_size_limit=${PORT25_SIZE}"
|
||||||
|
master_cf_set_smtp_inet_o smtpd_recipient_restrictions "${RECIPIENT_RESTRICTIONS}"
|
||||||
|
if [ -n "${INBOUND_MILTERS}" ]; then
|
||||||
|
master_cf_set_smtp_inet_o smtpd_milters "${INBOUND_MILTERS}"
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
postconf -MX "smtp/inet" 2>/dev/null || true
|
postconf -MX "smtp/inet" 2>/dev/null || true
|
||||||
postconf -MX "dmarc-ingest/unix-pipe" 2>/dev/null || true
|
postconf -MX "dmarc-ingest/unix-pipe" 2>/dev/null || true
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
selfpost:
|
selfpost:
|
||||||
image: ghcr.io/mixeme/selfpost:1.9.0
|
image: ghcr.io/mixeme/selfpost:1.9.1
|
||||||
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}"
|
||||||
|
|||||||
Reference in New Issue
Block a user