SelfPost · panel redesign · stage 1
-Three directions, three key screens
-Overview, an outbound domain and sign-in, drawn three ways. Pick one (or a mix); - the remaining screens are then drawn in that direction only. Serve this folder from the repository - root — the pages load the panel's own fonts and mark by relative path.
+SelfPost · panel redesign · stage 2
+The accepted direction, every screen
+Direction C (Bulma) was picked as the base: the important things in view, details one + or two clicks away. It takes the postal signature of A — the postmark verdict, numbered mono section + heads, the stamp's perforated edge — and the icons of B. Twenty-nine screens live in + panel/. Serve this folder from the repository root: the pages load the panel's own + fonts and mark by relative path.
+ +Screen map
+| Signed out | Sign in · Create administrator |
|---|---|
| Overview | Overview — postmark verdict, six health cards, both domain lists |
| Outbound | Domains · domain ·
+ domain settings · application form ·
+ password shown once · delete domain + Log · message · + Queue · DMARC reports · + by domain · one report |
| Inbound | Domains · domain · + delete domain · Log · + Queue (empty state) |
| Server | Health · System log · + Backup · Users · user form · + delete user · Settings |
| User menu | Account · Help |
What changed against today's panel
+-
+
- Overview shows verdicts, Health shows tables. Process lists, socket paths and interface counters moved to + Server › Health, one click from each card. +
- Every page is one of three layouts: a list (form on top, table below), a detail page (sticky side menu + + numbered boxes), or a form page (boxes in equal columns). No page picks its own width. +
- Own password is Account, instance defaults are Settings. Export sits with the domain, import with Backup, + and each links to the other. +
- Queues are tables, not a
postqueue -pdump — this needspostqueue -jparsing. + The inbound queue is the same queue filtered by recipient domain.
+ - Confirm pages say what will be lost as a list, beside a hint for the usual alternative (export before delete). +
- Own components on top of Bulma: postmark, perforated edge, numbered box head, health card, DNS record block, facts grid,
+ timeline, log pane. The mockup's
theme.cssis about 200 lines.
+ panel/build.pywraps the fragments inpanel/src/with the shared navbar; the built pages are committed, + so nothing has to be run to view them.
+
Stage 1 · three directions on three key screens
+Kept for the record: Overview, an outbound domain and sign-in, drawn three ways.
Shared by all three
-
diff --git a/docs/assets/panel-redesign/panel/account.html b/docs/assets/panel-redesign/panel/account.html
new file mode 100644
index 0000000..f617ef4
--- /dev/null
+++ b/docs/assets/panel-redesign/panel/account.html
@@ -0,0 +1,106 @@
+
+
+
+
+
+
- Reporter
- Outlook.com
- Report id
- 5f1c9a0e7b2d4e61a3
- Window
- 20 Sep 00:00 – 21 Sep 00:00 UTC
- Received
- 2026-09-21 04:40 UTC
- p / sp / pct
- none / none / 100
- adkim / aspf
- r / r
- rua
- dmarc@mail.example.org
- Last report
- 2026-09-21 06:12 UTC
- This week
- 14 kept · 0 parse failures
- Hosted address
- dmarc@mail.example.org
- Retention
- 500 reports or 90 days
- Expires
- 2026-10-03 09:14 UTC
- Names
- mail.example.org
- Hostname
- mail.example.org
- Lookup
- → 203.0.113.25
← mail.example.org - stop accepting mail for it on port 25 — senders get a relay-denied reply; +
- remove its upstream and its 4 listed recipients. +
- First retry
- 5 min
- Later retries
- doubling
- capped at 66 min
- Kept in queue
- 5 days
- Then
- bounced
- back to the original sender
- Server
- mail.example.org
- Port
- 465 SSL/TLS · 587 STARTTLS
- May send as
- *@example.org
- permanently delete its DKIM signing key; +
- delete both applications (prod-server, alerts) with their credentials and sender bindings; +
- reload OpenDKIM so the domain is no longer signed. +
- Server
- mail.example.org
- Port 465
- SSL/TLS (implicit)
- Port 587
- STARTTLS (submission)
- Authentication
- Application login, required on every port
- Domain
- example.org
- Application
- alerts
- Accepted
- 2026-09-21 13:58:07 UTC
- Status reported
- 2026-09-21 13:58:09 UTC
- Queue id
- 4XcB7k2Jm9z1
- Journal id
- 184220
- Accepted from alerts at 198.51.100.7 +
- Deferred — the receiving server asked to retry later +
- Still in the queue; kept for 5 days, then bounced +
- First retry
- 5 min
- Later retries
- doubling
- capped at 66 min
- Kept in queue
- 5 days
- Then
- bounced
- no attempt counter, only time
- Reporter
- Outlook.com
- Report id
- 5f1c9a0e7b2d4e61a3
- Window
- 20 Sep 00:00 – 21 Sep 00:00 UTC
- Received
- 2026-09-21 04:40 UTC
- p / sp / pct
- none / none / 100
- adkim / aspf
- r / r
- rua
- dmarc@mail.example.org
- Last report
- 2026-09-21 06:12 UTC
- This week
- 14 kept · 0 parse failures
- Hosted address
- dmarc@mail.example.org
- Retention
- 500 reports or 90 days
- Expires
- 2026-10-03 09:14 UTC
- Names
- mail.example.org
- Hostname
- mail.example.org
- Lookup
- → 203.0.113.25
← mail.example.org - stop accepting mail for it on port 25 — senders get a relay-denied reply; +
- remove its upstream and its 4 listed recipients. +
- First retry
- 5 min
- Later retries
- doubling
- capped at 66 min
- Kept in queue
- 5 days
- Then
- bounced
- back to the original sender
- Server
- mail.example.org
- Port
- 465 SSL/TLS · 587 STARTTLS
- May send as
- *@example.org
Signed in as admin · global administrator
+Account
+Your sign-in to this panel. Applications keep their own logins and passwords and are not affected.
+Panel credentials
What happens
Changing the password signs out every other session of this account. This one stays signed in.
+A domain administrator sees this same page, and nothing under Server.
+Server
+Backup
+Take the whole instance with you, or bring one domain in from another SelfPost. Both files are secrets.
+Full backup
data/ (database, DKIM keys, credentials, the queue), docker-compose.yml, .env and certs/ in one archive. Restore into an empty project directory and start the same SelfPost version. The reverse-proxy vhost is not included.
Import a domain
A domain export from another instance — plain .json or encrypted .spde. Its DKIM key and application passwords come across, so the published DNS needs no change. The export itself is made on the domain's settings.
shop.example.org
+11 204 pass · 41 fail in the last 7 days. Failures come from a source that is not this relay — review before tightening p=.
Sources · 7 days
| Source | Pass | Fail | Disposition |
|---|---|---|---|
| 203.0.113.25 this relay | 11 204 | 0 | none |
| 198.51.100.44 | 0 | 41 | none |
DMARC reports / shop.example.org /
+Outlook.com · 20 Sep 2026
+shop.example.org1 903 pass7 fail
+Report
-
+
Published policy
-
+
Records
| Source | Count | Disposition | SPF | DKIM | Header from |
|---|---|---|---|---|---|
| 203.0.113.25 this relay | 1 903 | none | pass | pass | shop.example.org |
| 198.51.100.44 | 7 | none | fail | fail | shop.example.org |
Outbound
+DMARC reports
+How receivers saw mail claiming to be from your domains. Aggregate (rua=) only; open a report for the parsed XML.
Ingest
-
+
Recent reports
| Received, UTC | Domain | Reporter | Window | Pass | Fail | |
|---|---|---|---|---|---|---|
| 09-21 06:12 | example.org | google.com | 20 Sep | 412 | 0 | View |
| 09-21 04:40 | shop.example.org | Outlook.com | 20 Sep | 1 903 | 7 | View |
| 09-20 23:58 | example.org | Yahoo | 19 Sep | 38 | 0 | View |
| 09-20 06:09 | notify.acme.io | google.com | 19 Sep | 61 | 0 | View |
Server
+Health
+Everything behind the six cards on Overview. Refreshes every 10 s.
+Machine
| Resource | Usage | Detail |
|---|---|---|
| CPU | 12 % | 2 cores, load 0.21 |
| Memory | 41 % | 812 MB of 1.9 GB |
| Network | ↓ 18 kB/s · ↑ 44 kB/s | eth0: 2.1 GB in, 6.4 GB out |
Processes
| Program | State | Detail |
|---|---|---|
| postfix | running | pid 41, uptime 18 days |
| opendkim | running | pid 39, uptime 18 days |
| journal-milter | running | pid 40, uptime 18 days |
| panel | running | pid 44, uptime 18 days |
| dmarc-ingest | running | pid 47, uptime 18 days |
TLS certificate
-
+
Expires in 12 days — renewal has not run.
+Renewal normally runs 30 days before expiry. Check that port 80 is reachable and look for acme lines in the system log.
Milter sockets
| Milter | State |
|---|---|
| opendkim inet:127.0.0.1:8891 | ok |
| journal-milter unix:/run/selfpost/journal.sock | ok |
Hostname and reverse DNS
-
+
Reference
+Help
+What each screen checks and what to do when it is not green. Every numbered section on a page links to its topic here.
+Overview
Health checks
Six checks, the worst of them is the postmark. ok needs nothing; warn still delivers mail but will stop doing so if ignored; fail means mail is being lost or refused now.
TLS certificate
The certificate Postfix presents on 465 and 587. It warns 14 days before expiry and fails once expired — clients that verify certificates then refuse to connect.
Hostname and reverse DNS
The hostname must resolve to this server's address, and that address must resolve back to the hostname. Large receivers reject or spam-folder mail from hosts where the two disagree. The PTR record is set at your hosting provider, not in your DNS zone.
Outbound
DNS records
DKIM proves the message was signed by this relay, SPF lists the addresses allowed to send for the domain, DMARC tells receivers what to do when both fail and where to report. Publish all three exactly as shown; merge SPF into an existing record rather than adding a second one.
Applications
An application is one SASL login. It may send as any address of its domain or only as listed addresses. The password is shown once at creation or regeneration and is not stored in readable form.
Rate limits
Level 1 is a per-IP ceiling set in .env. Level 2 is optional, per domain and per application, manual or computed from 30-day statistics, and can never exceed level 1.
Inbound domains / lists.example.org /
+Delete lists.example.org
+This cannot be undone
Deleting the inbound domain lists.example.org will:
+-
+
Remove or repoint the MX record first, or mail for the domain will bounce. Outbound domains are not touched.
+ +lists.example.org
+Accepted on port 25, handed to mx.internal:25 over required TLS · 4 recipients
+MX record
MX
publishedKeep any existing primary MX if this is a backup-MXUpstream
Valid recipients
Inbound
+Inbound domains
+Backup-MX / forwarder. Port 25 accepts mail only for the domains listed here and hands it to their upstream. No mailboxes.
+Add a domain
Domains
| Domain | DNS | Upstream | Recipients | TLS to upstream | |
|---|---|---|---|---|---|
| lists.example.org | MX | mx.internal:25 | 4 addresses | required | OpenDelete |
| acme.io | MX | 10.0.4.12:2525 | any address | opportunistic | OpenDelete |
Inbound
+Inbound log
+What port 25 accepted and what it turned away. Accepts come from the inbound journal, rejects from mail.log.
Messages
+ +| Time, UTC | From | To | Subject | Action | Reason |
|---|---|---|---|---|---|
| 09-21 14:00:18 | t.berg@uni.example | dev@lists.example.org | Re: [dev] patch series v3 | forwarded | → mx.internal:25 |
| 09-21 13:57:41 | promo@bulk.example | sales@lists.example.org | — | rejected | 550 5.1.1 unknown recipient |
| 09-21 13:44:02 | hr@partner.example | jobs@acme.io | Application: backend engineer | deferred | upstream 10.0.4.12 timed out |
| 09-21 13:30:55 | noreply@github.example | security@lists.example.org | [advisory] new report | forwarded | → mx.internal:25 |
Inbound
+Inbound queue
+Mail accepted on port 25 and still waiting for its upstream. The same Postfix queue as outbound, filtered by recipient domain.
+Waiting
How retries work
-
+
YOUR SMTP. YOUR RULES.
+© 2026 Mix · License (AGPL-3.0) · Source · No warranty
+Outbound domains / example.org / Applications /
+New password for prod-server
+Shown once
The previous password stopped working when this one was generated. If this one is lost, generate another.
Connect with
-
+
Outbound domains / example.org / Applications /
+prod-server
+1 102 messages in 30 days · peak 96 msg/h · average 1.5 msg/h. The same form, empty, adds a new application.
+Outbound domains / example.org /
+Delete example.org
+This cannot be undone
Deleting example.org will:
+-
+
The published DKIM record becomes invalid — remove it from DNS unless you plan to re-add the domain. Inbound domains are not touched.
+ +Moving it instead?
Export the domain first. The file carries the key and the application passwords, so the new instance needs no DNS change.
+Outbound domains / example.org /
+Domain settings
+The things set once and rarely touched: where DMARC reports go, the sending ceiling, moving the domain elsewhere.
+DMARC report address
Export domain
One file with the DKIM key and every application's password hash — import it on another SelfPost and the published DNS needs no change. The file is a secret.
+ +Rate limit
Applies to every sender on this domain and cannot exceed level 1 (600 messages / 3600 s per client IP, set in .env). An application may carry its own limit above or below this one.
Delete domain
Removes the DKIM key and both applications. Asks once more before doing it.
+ Delete example.org… +example.org
+1 284 messages in 30 days · peak 96 msg/h · average 1.8 msg/h
+DNS records
DKIM
publishedNot a secret · selectorsp2026SPF
mismatchMerge into the existing record — never publish a second oneThe published record does not authorize 203.0.113.25. Add ip4:203.0.113.25 before ~all. Shallow check: include: is not followed.
p=none does not affect delivery. Tighten to quarantine, then reject, once the reports look clean.
Applications
| Login | May send as | 30 days | Limits | |
|---|---|---|---|---|
| prod-server | *@example.org | 1 102 msg · peak 96/h | 200 / h | +EditNew passwordDelete |
| alerts | alerts@example.org, noc@example.org | 182 msg · peak 14/h | domain 2 IPs | +EditNew passwordDelete |
Connection
-
+
Outbound
+Outbound domains
+Domains this relay signs and sends for. Each gets a DKIM key and its own application logins.
+Add a domain
Domains
| Domain | DNS | Selector | Apps | 30 days | |
|---|---|---|---|---|---|
| example.org | DKIM SPF DMARC | sp2026 | 2 | 1 284 msg · peak 96/h | OpenDelete |
| shop.example.org | DKIM SPF DMARC | sp2026 | 1 | 18 920 msg · peak 410/h | OpenDelete |
| notify.acme.io | DKIM SPF DMARC | sp2025 | 3 | 402 msg · peak 22/h | OpenDelete |
Outbound
+Outbound log
+Every message an application handed to the relay. Rows older than 30 days are deleted — change that in Settings.
+Messages
+ +| Time, UTC | From | To | Subject | Status | |
|---|---|---|---|---|---|
| 09-21 14:01:52 | shop@shop.example.org | m.keller@gmx.de | Your order #48213 has shipped | sent | Details |
| 09-21 14:01:50 | shop@shop.example.org | anna.lind@outlook.com | Your order #48212 has shipped | sent | Details |
| 09-21 13:58:07 | alerts@example.org | noc@example.org | [FIRING] disk usage above 90 % on db-2 | deferred | Details |
| 09-21 13:41:19 | no-reply@notify.acme.io | j.doe@nonexistent.example | Reset your password | bounced | Details |
| 09-21 13:40:02 | prod@example.org | billing@partner.example | Invoice 2026-0917 | rate-limited | Details |
| 09-21 13:12:44 | shop@shop.example.org | p.novak@seznam.cz | We received your return request | sent | Details |
[FIRING] disk usage above 90 % on db-2
+alerts@example.orgnoc@example.orgdeferred
+Message
-
+
History
-
+
Delivery log
mail.log with this queue id13:58:07 postfix/smtpd[2114]: 4XcB7k2Jm9z1: client=unknown[198.51.100.7], sasl_username=alerts +13:58:07 postfix/cleanup[2120]: 4XcB7k2Jm9z1: message-id=<a81f0c@alertmanager> +13:58:07 opendkim[39]: 4XcB7k2Jm9z1: DKIM-Signature field added (s=sp2026, d=example.org) +13:58:09 postfix/smtp[2123]: 4XcB7k2Jm9z1: to=<noc@example.org>, relay=mx1.example.org[192.0.2.10]:25, delay=1.9, status=deferred (host mx1.example.org said: 451 4.7.1 Greylisted, try again in 5 minutes)+
Outbound
+Outbound queue
+Messages accepted from applications and still waiting for the receiving server. Refreshes every 10 s.
+Waiting
| Queue id | Arrived, UTC | From | To | Last reply | |
|---|---|---|---|---|---|
| 4XcB7k2Jm9z1 | 09-21 13:58:07 | alerts@example.org | noc@example.org | 451 4.7.1 Greylisted, try again in 5 minutes | Details |
How retries work
-
+
mail.example.org
+Mail is flowing. One thing needs attention.
+The TLS certificate expires in 12 days and has not renewed yet.
+refreshes every 10 s
| Domain | DNS | Apps | 30 days |
|---|---|---|---|
| example.org | DKIM SPF DMARC | 2 | 1 284 msg |
| shop.example.org | DKIM SPF DMARC | 1 | 18 920 msg |
| notify.acme.io | DKIM SPF DMARC | 3 | 402 msg |
| Domain | MX | Upstream |
|---|---|---|
| lists.example.org | MX | mx.internal:25 |
| acme.io | MX | 10.0.4.12:2525 |
Server
+Settings
+Defaults for the whole instance. Your own username and password are under Account.
+YOUR SMTP. YOUR RULES.
+© 2026 Mix · License (AGPL-3.0) · Source · No warranty
+Signed in as admin · global administrator
+Account
+Your sign-in to this panel. Applications keep their own logins and passwords and are not affected.
+Panel credentials
What happens
Changing the password signs out every other session of this account. This one stays signed in.
+A domain administrator sees this same page, and nothing under Server.
+Server
+Backup
+Take the whole instance with you, or bring one domain in from another SelfPost. Both files are secrets.
+Full backup
data/ (database, DKIM keys, credentials, the queue), docker-compose.yml, .env and certs/ in one archive. Restore into an empty project directory and start the same SelfPost version. The reverse-proxy vhost is not included.
Import a domain
A domain export from another instance — plain .json or encrypted .spde. Its DKIM key and application passwords come across, so the published DNS needs no change. The export itself is made on the domain's settings.
shop.example.org
+11 204 pass · 41 fail in the last 7 days. Failures come from a source that is not this relay — review before tightening p=.
Sources · 7 days
| Source | Pass | Fail | Disposition |
|---|---|---|---|
| 203.0.113.25 this relay | 11 204 | 0 | none |
| 198.51.100.44 | 0 | 41 | none |
DMARC reports / shop.example.org /
+Outlook.com · 20 Sep 2026
+shop.example.org1 903 pass7 fail
+Report
-
+
Published policy
-
+
Records
| Source | Count | Disposition | SPF | DKIM | Header from |
|---|---|---|---|---|---|
| 203.0.113.25 this relay | 1 903 | none | pass | pass | shop.example.org |
| 198.51.100.44 | 7 | none | fail | fail | shop.example.org |
Outbound
+DMARC reports
+How receivers saw mail claiming to be from your domains. Aggregate (rua=) only; open a report for the parsed XML.
Ingest
-
+
Recent reports
| Received, UTC | Domain | Reporter | Window | Pass | Fail | |
|---|---|---|---|---|---|---|
| 09-21 06:12 | example.org | google.com | 20 Sep | 412 | 0 | View |
| 09-21 04:40 | shop.example.org | Outlook.com | 20 Sep | 1 903 | 7 | View |
| 09-20 23:58 | example.org | Yahoo | 19 Sep | 38 | 0 | View |
| 09-20 06:09 | notify.acme.io | google.com | 19 Sep | 61 | 0 | View |
Server
+Health
+Everything behind the six cards on Overview. Refreshes every 10 s.
+Machine
| Resource | Usage | Detail |
|---|---|---|
| CPU | 12 % | 2 cores, load 0.21 |
| Memory | 41 % | 812 MB of 1.9 GB |
| Network | ↓ 18 kB/s · ↑ 44 kB/s | eth0: 2.1 GB in, 6.4 GB out |
Processes
| Program | State | Detail |
|---|---|---|
| postfix | running | pid 41, uptime 18 days |
| opendkim | running | pid 39, uptime 18 days |
| journal-milter | running | pid 40, uptime 18 days |
| panel | running | pid 44, uptime 18 days |
| dmarc-ingest | running | pid 47, uptime 18 days |
TLS certificate
-
+
Expires in 12 days — renewal has not run.
+Renewal normally runs 30 days before expiry. Check that port 80 is reachable and look for acme lines in the system log.
Milter sockets
| Milter | State |
|---|---|
| opendkim inet:127.0.0.1:8891 | ok |
| journal-milter unix:/run/selfpost/journal.sock | ok |
Hostname and reverse DNS
-
+
Reference
+Help
+What each screen checks and what to do when it is not green. Every numbered section on a page links to its topic here.
+Overview
Health checks
Six checks, the worst of them is the postmark. ok needs nothing; warn still delivers mail but will stop doing so if ignored; fail means mail is being lost or refused now.
TLS certificate
The certificate Postfix presents on 465 and 587. It warns 14 days before expiry and fails once expired — clients that verify certificates then refuse to connect.
Hostname and reverse DNS
The hostname must resolve to this server's address, and that address must resolve back to the hostname. Large receivers reject or spam-folder mail from hosts where the two disagree. The PTR record is set at your hosting provider, not in your DNS zone.
Outbound
DNS records
DKIM proves the message was signed by this relay, SPF lists the addresses allowed to send for the domain, DMARC tells receivers what to do when both fail and where to report. Publish all three exactly as shown; merge SPF into an existing record rather than adding a second one.
Applications
An application is one SASL login. It may send as any address of its domain or only as listed addresses. The password is shown once at creation or regeneration and is not stored in readable form.
Rate limits
Level 1 is a per-IP ceiling set in .env. Level 2 is optional, per domain and per application, manual or computed from 30-day statistics, and can never exceed level 1.
Inbound domains / lists.example.org /
+Delete lists.example.org
+This cannot be undone
Deleting the inbound domain lists.example.org will:
+-
+
Remove or repoint the MX record first, or mail for the domain will bounce. Outbound domains are not touched.
+ +lists.example.org
+Accepted on port 25, handed to mx.internal:25 over required TLS · 4 recipients
+MX record
MX
publishedKeep any existing primary MX if this is a backup-MXUpstream
Valid recipients
Inbound
+Inbound domains
+Backup-MX / forwarder. Port 25 accepts mail only for the domains listed here and hands it to their upstream. No mailboxes.
+Add a domain
Domains
| Domain | DNS | Upstream | Recipients | TLS to upstream | |
|---|---|---|---|---|---|
| lists.example.org | MX | mx.internal:25 | 4 addresses | required | OpenDelete |
| acme.io | MX | 10.0.4.12:2525 | any address | opportunistic | OpenDelete |
Inbound
+Inbound log
+What port 25 accepted and what it turned away. Accepts come from the inbound journal, rejects from mail.log.
Messages
+ +| Time, UTC | From | To | Subject | Action | Reason |
|---|---|---|---|---|---|
| 09-21 14:00:18 | t.berg@uni.example | dev@lists.example.org | Re: [dev] patch series v3 | forwarded | → mx.internal:25 |
| 09-21 13:57:41 | promo@bulk.example | sales@lists.example.org | — | rejected | 550 5.1.1 unknown recipient |
| 09-21 13:44:02 | hr@partner.example | jobs@acme.io | Application: backend engineer | deferred | upstream 10.0.4.12 timed out |
| 09-21 13:30:55 | noreply@github.example | security@lists.example.org | [advisory] new report | forwarded | → mx.internal:25 |
Inbound
+Inbound queue
+Mail accepted on port 25 and still waiting for its upstream. The same Postfix queue as outbound, filtered by recipient domain.
+Waiting
How retries work
-
+
YOUR SMTP. YOUR RULES.
+© 2026 Mix · License (AGPL-3.0) · Source · No warranty
+Outbound domains / example.org / Applications /
+New password for prod-server
+Shown once
The previous password stopped working when this one was generated. If this one is lost, generate another.
Connect with
-
+
Outbound domains / example.org / Applications /
+prod-server
+1 102 messages in 30 days · peak 96 msg/h · average 1.5 msg/h. The same form, empty, adds a new application.
+Outbound domains / example.org /
+Delete example.org
+This cannot be undone
Deleting example.org will:
+-
+
- permanently delete its DKIM signing key; +
- delete both applications (prod-server, alerts) with their credentials and sender bindings; +
- reload OpenDKIM so the domain is no longer signed. +
The published DKIM record becomes invalid — remove it from DNS unless you plan to re-add the domain. Inbound domains are not touched.
+ +Moving it instead?
Export the domain first. The file carries the key and the application passwords, so the new instance needs no DNS change.
+Outbound domains / example.org /
+Domain settings
+The things set once and rarely touched: where DMARC reports go, the sending ceiling, moving the domain elsewhere.
+DMARC report address
Export domain
One file with the DKIM key and every application's password hash — import it on another SelfPost and the published DNS needs no change. The file is a secret.
+ +Rate limit
Applies to every sender on this domain and cannot exceed level 1 (600 messages / 3600 s per client IP, set in .env). An application may carry its own limit above or below this one.
Delete domain
Removes the DKIM key and both applications. Asks once more before doing it.
+ Delete example.org… +example.org
+1 284 messages in 30 days · peak 96 msg/h · average 1.8 msg/h
+DNS records
DKIM
publishedNot a secret · selectorsp2026SPF
mismatchMerge into the existing record — never publish a second oneThe published record does not authorize 203.0.113.25. Add ip4:203.0.113.25 before ~all. Shallow check: include: is not followed.
p=none does not affect delivery. Tighten to quarantine, then reject, once the reports look clean.
Applications
| Login | May send as | 30 days | Limits | |
|---|---|---|---|---|
| prod-server | *@example.org | 1 102 msg · peak 96/h | 200 / h | +EditNew passwordDelete |
| alerts | alerts@example.org, noc@example.org | 182 msg · peak 14/h | domain 2 IPs | +EditNew passwordDelete |
Connection
-
+
- Server
- mail.example.org
- Port 465
- SSL/TLS (implicit)
- Port 587
- STARTTLS (submission)
- Authentication
- Application login, required on every port
Outbound
+Outbound domains
+Domains this relay signs and sends for. Each gets a DKIM key and its own application logins.
+Add a domain
Domains
| Domain | DNS | Selector | Apps | 30 days | |
|---|---|---|---|---|---|
| example.org | DKIM SPF DMARC | sp2026 | 2 | 1 284 msg · peak 96/h | OpenDelete |
| shop.example.org | DKIM SPF DMARC | sp2026 | 1 | 18 920 msg · peak 410/h | OpenDelete |
| notify.acme.io | DKIM SPF DMARC | sp2025 | 3 | 402 msg · peak 22/h | OpenDelete |
Outbound
+Outbound log
+Every message an application handed to the relay. Rows older than 30 days are deleted — change that in Settings.
+Messages
+ +| Time, UTC | From | To | Subject | Status | |
|---|---|---|---|---|---|
| 09-21 14:01:52 | shop@shop.example.org | m.keller@gmx.de | Your order #48213 has shipped | sent | Details |
| 09-21 14:01:50 | shop@shop.example.org | anna.lind@outlook.com | Your order #48212 has shipped | sent | Details |
| 09-21 13:58:07 | alerts@example.org | noc@example.org | [FIRING] disk usage above 90 % on db-2 | deferred | Details |
| 09-21 13:41:19 | no-reply@notify.acme.io | j.doe@nonexistent.example | Reset your password | bounced | Details |
| 09-21 13:40:02 | prod@example.org | billing@partner.example | Invoice 2026-0917 | rate-limited | Details |
| 09-21 13:12:44 | shop@shop.example.org | p.novak@seznam.cz | We received your return request | sent | Details |
[FIRING] disk usage above 90 % on db-2
+alerts@example.orgnoc@example.orgdeferred
+Message
-
+
- Domain
- example.org
- Application
- alerts
- Accepted
- 2026-09-21 13:58:07 UTC
- Status reported
- 2026-09-21 13:58:09 UTC
- Queue id
- 4XcB7k2Jm9z1
- Journal id
- 184220
History
-
+
- Accepted from alerts at 198.51.100.7 +
- Deferred — the receiving server asked to retry later +
- Still in the queue; kept for 5 days, then bounced +
Delivery log
mail.log with this queue id13:58:07 postfix/smtpd[2114]: 4XcB7k2Jm9z1: client=unknown[198.51.100.7], sasl_username=alerts +13:58:07 postfix/cleanup[2120]: 4XcB7k2Jm9z1: message-id=<a81f0c@alertmanager> +13:58:07 opendkim[39]: 4XcB7k2Jm9z1: DKIM-Signature field added (s=sp2026, d=example.org) +13:58:09 postfix/smtp[2123]: 4XcB7k2Jm9z1: to=<noc@example.org>, relay=mx1.example.org[192.0.2.10]:25, delay=1.9, status=deferred (host mx1.example.org said: 451 4.7.1 Greylisted, try again in 5 minutes)+
Outbound
+Outbound queue
+Messages accepted from applications and still waiting for the receiving server. Refreshes every 10 s.
+Waiting
| Queue id | Arrived, UTC | From | To | Last reply | |
|---|---|---|---|---|---|
| 4XcB7k2Jm9z1 | 09-21 13:58:07 | alerts@example.org | noc@example.org | 451 4.7.1 Greylisted, try again in 5 minutes | Details |
How retries work
-
+
- First retry
- 5 min
- Later retries
- doubling
- capped at 66 min
- Kept in queue
- 5 days
- Then
- bounced
- no attempt counter, only time
mail.example.org
+Mail is flowing. One thing needs attention.
+The TLS certificate expires in 12 days and has not renewed yet.
+refreshes every 10 s
| Domain | DNS | Apps | 30 days |
|---|---|---|---|
| example.org | DKIM SPF DMARC | 2 | 1 284 msg |
| shop.example.org | DKIM SPF DMARC | 1 | 18 920 msg |
| notify.acme.io | DKIM SPF DMARC | 3 | 402 msg |
| Domain | MX | Upstream |
|---|---|---|
| lists.example.org | MX | mx.internal:25 |
| acme.io | MX | 10.0.4.12:2525 |
Server
+Settings
+Defaults for the whole instance. Your own username and password are under Account.
+YOUR SMTP. YOUR RULES.
+© 2026 Mix · License (AGPL-3.0) · Source · No warranty
+Server
+System log
+The tail of mail.log — Postfix, OpenDKIM and the milters. For one message, open it from a log page instead.
Recent lines
Sep 21 14:01:52 postfix/smtp[2131]: 4XcB9q0Lw2z1: to=<m.keller@gmx.de>, relay=mx00.gmx.net[212.227.15.9]:25, delay=0.8, status=sent (250 Requested mail action okay) +Sep 21 14:01:52 postfix/qmgr[58]: 4XcB9q0Lw2z1: removed +Sep 21 14:00:18 postfix/smtpd[2129]: connect from mail.uni.example[192.0.2.77] +Sep 21 14:00:18 postfix/smtp[2130]: 4XcB8z5Tn1z1: to=<dev@lists.example.org>, relay=mx.internal[10.0.4.2]:25, status=sent (250 2.0.0 Ok: queued) +Sep 21 13:58:09 postfix/smtp[2123]: 4XcB7k2Jm9z1: to=<noc@example.org>, relay=mx1.example.org[192.0.2.10]:25, status=deferred (451 4.7.1 Greylisted, try again in 5 minutes) +Sep 21 13:57:41 postfix/smtpd[2119]: NOQUEUE: reject: RCPT from bulk.example[198.51.100.90]: 550 5.1.1 <sales@lists.example.org>: Recipient address rejected: unknown recipient +Sep 21 13:44:02 postfix/smtp[2101]: 4XcB2m7Hd4z1: to=<jobs@acme.io>, relay=none, status=deferred (connect to 10.0.4.12[10.0.4.12]:2525: Connection timed out) +Sep 21 13:41:19 postfix/smtp[2098]: 4XcB1c3Rk8z1: to=<j.doe@nonexistent.example>, status=bounced (Host or domain name not found) +Sep 21 13:40:02 journal-milter[40]: rate limit: app=prod-server 201/200 in 3600s — tempfail at MAIL FROM +Sep 21 13:00:00 opendkim[39]: key table reloaded (3 domains)+
This cannot be undone
Deleting the panel user shop-team will:
+-
+
- end any signed-in session of this user at once; +
- remove the assignment to shop.example.org. +
The domain, its applications and their passwords are not affected.
+ +Server
+Users
+Who may sign in to this panel. A domain administrator sees only the outbound domains assigned to them.
+Panel users
| Username | Role | Domains | |
|---|---|---|---|
| admin you | global | All | Edit |
| shop-team | domain admin | shop.example.org | Edit |
| acme-ops | domain admin | notify.acme.io | Edit |
Server
+System log
+The tail of mail.log — Postfix, OpenDKIM and the milters. For one message, open it from a log page instead.
Recent lines
Sep 21 14:01:52 postfix/smtp[2131]: 4XcB9q0Lw2z1: to=<m.keller@gmx.de>, relay=mx00.gmx.net[212.227.15.9]:25, delay=0.8, status=sent (250 Requested mail action okay) +Sep 21 14:01:52 postfix/qmgr[58]: 4XcB9q0Lw2z1: removed +Sep 21 14:00:18 postfix/smtpd[2129]: connect from mail.uni.example[192.0.2.77] +Sep 21 14:00:18 postfix/smtp[2130]: 4XcB8z5Tn1z1: to=<dev@lists.example.org>, relay=mx.internal[10.0.4.2]:25, status=sent (250 2.0.0 Ok: queued) +Sep 21 13:58:09 postfix/smtp[2123]: 4XcB7k2Jm9z1: to=<noc@example.org>, relay=mx1.example.org[192.0.2.10]:25, status=deferred (451 4.7.1 Greylisted, try again in 5 minutes) +Sep 21 13:57:41 postfix/smtpd[2119]: NOQUEUE: reject: RCPT from bulk.example[198.51.100.90]: 550 5.1.1 <sales@lists.example.org>: Recipient address rejected: unknown recipient +Sep 21 13:44:02 postfix/smtp[2101]: 4XcB2m7Hd4z1: to=<jobs@acme.io>, relay=none, status=deferred (connect to 10.0.4.12[10.0.4.12]:2525: Connection timed out) +Sep 21 13:41:19 postfix/smtp[2098]: 4XcB1c3Rk8z1: to=<j.doe@nonexistent.example>, status=bounced (Host or domain name not found) +Sep 21 13:40:02 journal-milter[40]: rate limit: app=prod-server 201/200 in 3600s — tempfail at MAIL FROM +Sep 21 13:00:00 opendkim[39]: key table reloaded (3 domains)+
This cannot be undone
Deleting the panel user shop-team will:
+-
+
- end any signed-in session of this user at once; +
- remove the assignment to shop.example.org. +
The domain, its applications and their passwords are not affected.
+ +Server
+Users
+Who may sign in to this panel. A domain administrator sees only the outbound domains assigned to them.
+