Hosted mailboxes (SPEC App. D), behind HOSTED_MAILBOXES (off: unchanged):
- Stalwart mail server, provisioned by `python -m app.hosted.provision`;
directory read from a Postgres view, app passwords only for mail apps
- native account per user, the worker signs in as master for the user
- raw messages of hosted mailboxes only cached, fetched back on demand
- migrations 0025 (accounts.kind, directory view), 0026 (IMAP ids bigint)
Mail:
- dark message mode switch in the reading pane (Thunderbird's algorithm)
- moves and folder creation quote the folder name ("Deleted Items"):
swipe-to-delete / Trash no longer bounce back
- thread unread counters: lock before recount, sorted lock order,
UIDVALIDITY re-import recounts, nightly repair_threads
- sidebar accounts sorted alphabetically, more space above headings
Settings: Security headings renamed; antispam accounts are explicit
(none ticked = none filtered), input widths, Activity hidden.
Plugin bundles served with Cache-Control: no-cache.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
118 lines
5.5 KiB
Markdown
118 lines
5.5 KiB
Markdown
# Hosted mail (M6): network and DNS plan
|
|
|
|
Notes for switching `ultimo.email` mail from home.pl to Ultimo's own mail server
|
|
(Stalwart on the QNAP). Companion to the M6 plan in
|
|
`webmail-client-spec_v1.5.md` Appendix D. Gathered 2026-10-09/10.
|
|
|
|
## Decisions
|
|
|
|
| | Decision |
|
|
|---|---|
|
|
| Hosting | **Everything on the QNAP** — receive and send directly (spec §D.1 option A). A relay (home.pl SMTP, SMTP2GO, Brevo) is optional, as a fallback only. |
|
|
| Domain | Addresses `name@ultimo.email`; webmail stays at `https://ultimo.email`. |
|
|
| Mail apps | **Allowed**: Thunderbird and phone mail apps use the mailboxes over IMAP/SMTP, signing in with **app passwords** only (never the webmail password). |
|
|
| Mail host name | **`mail.ultimo.email`** (recommended; `ultimo.email` would also work, see below). |
|
|
|
|
## Current setup
|
|
|
|
- Static public IP **`178.219.143.96`** (ISP: Multiplay).
|
|
- Traffic → **router** → **Synology DSM** → DSM **reverse proxy** → **QNAP** (the webmail).
|
|
- All DNS records are at **home.pl**:
|
|
- A `ultimo.email` → `178.219.143.96` (the QNAP, through the Synology);
|
|
- MX `ultimo.email` → `serwer2295308.home.pl` — **mail is still at home.pl**;
|
|
- other records also point at home.pl.
|
|
|
|
## Checks of the connection (2026-10-10)
|
|
|
|
| Check | Result |
|
|
|---|---|
|
|
| Blocklists — Spamhaus ZEN (incl. PBL), Barracuda, SpamCop, SORBS, UCEPROTECT | **Not listed** |
|
|
| Outbound port 25 (tested on the QNAP) | **Open** |
|
|
| Reverse DNS of `178.219.143.96` | `pub-143.96.multiplay.pl` — generic: **must change** (below) |
|
|
| Inbound 25 / 465 / 587 / 993 from outside | Time out — expected: not forwarded yet, nothing listening. Re-test after setup. |
|
|
| Inbound 443 | Open (webmail) |
|
|
|
|
## To do before switching
|
|
|
|
### 1. Reverse DNS (ask Multiplay)
|
|
|
|
Set the reverse DNS (PTR) of `178.219.143.96` to **`mail.ultimo.email`**.
|
|
|
|
Why: receiving servers (Gmail, Outlook…) check that three things agree — the
|
|
IP's reverse DNS name, that name's A record pointing back to the IP, and the
|
|
name the mail server introduces itself with (its SMTP greeting). A generic ISP
|
|
name or a mismatch reads as a hijacked home computer and hurts delivery.
|
|
`ultimo.email` itself would work too (its A record already points here); a
|
|
separate `mail.` name keeps mail working if the website ever moves elsewhere.
|
|
|
|
### 2. Router: forward the mail ports straight to the QNAP
|
|
|
|
DSM's reverse proxy carries only web traffic (HTTP/HTTPS); SMTP and IMAP are
|
|
other protocols, so these ports go from the router directly to the QNAP:
|
|
|
|
| Outside port | To | Purpose |
|
|
|---|---|---|
|
|
| 443, 80 | Synology (as today) | webmail, CalDAV/CardDAV (`/dav/`, `/.well-known/…`), certificates |
|
|
| **25** | QNAP | receiving mail from other servers (must be 25: MX delivery always uses it) |
|
|
| **465** | QNAP | sending from mail apps (SMTP over TLS) |
|
|
| **587** | QNAP | sending from mail apps (SMTP + STARTTLS) |
|
|
| **993** | QNAP | mail apps reading mail (IMAP over TLS) |
|
|
|
|
Mail sent by the QNAP leaves through the same router, i.e. from
|
|
`178.219.143.96` — the address the reverse DNS names.
|
|
|
|
### 3. The container's ports
|
|
|
|
Stalwart listens inside its container on the standard ports; Docker publishes
|
|
them on the QNAP — the same numbers if free (`"25:25"`, `"465:465"`, `"587:587"`,
|
|
`"993:993"`), or any free QNAP port (e.g. `"2525:25"`) with the router mapping
|
|
the standard outside port to it. Outside ports stay standard: 25 is mandatory,
|
|
and mail apps assume 465/587/993 when setting up an account.
|
|
|
|
Verify after setup: Stalwart must see the **real IP** of connecting servers and
|
|
apps (not a Docker address) — its spam checks and sign-in throttling use it.
|
|
|
|
### 4. TLS certificate for the mail server
|
|
|
|
The Synology holds the HTTPS certificate, but IMAP/SMTP connections end at the
|
|
QNAP, so Stalwart needs its own for `mail.ultimo.email`. Options:
|
|
|
|
- **(recommended)** Stalwart's own Let's Encrypt certificate: Let's Encrypt
|
|
checks over port 80, which goes to the Synology — add a **DSM reverse-proxy
|
|
rule: host `mail.ultimo.email`, port 80 → QNAP, Stalwart's HTTP port**.
|
|
Renews itself.
|
|
- DNS-based check, if home.pl's DNS can be updated automatically.
|
|
- Copy the Synology's certificate to the QNAP after every renewal (clumsiest).
|
|
|
|
### 5. DNS records at home.pl (at switch-over)
|
|
|
|
Lower the TTLs a day before.
|
|
|
|
| Record | Value |
|
|
|---|---|
|
|
| A `mail.ultimo.email` | `178.219.143.96` |
|
|
| MX `ultimo.email` | `10 mail.ultimo.email.` (replaces `serwer2295308.home.pl`) |
|
|
| TXT `ultimo.email` (SPF) | `v=spf1 mx -all` (add the relay's include if one is used) |
|
|
| TXT `<selector>._domainkey.ultimo.email` (DKIM) | the public key Stalwart generates |
|
|
| TXT `_dmarc.ultimo.email` | `v=DMARC1; p=none; rua=mailto:postmaster@ultimo.email` — watch the reports, then move to `quarantine` / `reject` |
|
|
| (optional) `autoconfig` / SRV records | so Thunderbird and phones find the server settings by themselves |
|
|
| (optional) MTA-STS, TLS-RPT | enforce encrypted delivery to us |
|
|
|
|
### 6. Moving the existing mail from home.pl
|
|
|
|
1. Create the mailboxes in Ultimo.
|
|
2. Copy each home.pl mailbox into its new one over IMAP.
|
|
3. Switch the MX.
|
|
4. Keep the home.pl account in the webmail for a while to catch mail that
|
|
still arrives there (DNS caches), then remove it.
|
|
|
|
### 7. Checks after switching
|
|
|
|
- From outside: ports 25 / 465 / 587 / 993 answer (with a TLS certificate for
|
|
`mail.ultimo.email`).
|
|
- Reverse DNS → `mail.ultimo.email` → `178.219.143.96`, and Stalwart greets as
|
|
`mail.ultimo.email`.
|
|
- Mail to and from Gmail and Outlook: headers show SPF, DKIM and DMARC **pass**,
|
|
delivered to the inbox (not spam).
|
|
- Thunderbird sets up an account with just the address and an app password.
|