# Email Service Architecture — Kaburu MSP
Status: DRAFT — pending Steve's review Created: 2026-08-19 Author: Gwen (agent)
## Problem
Email was added incrementally without a standard architecture. Each domain was configured ad-hoc — different MX targets, inconsistent SPF/DKIM, manual SNI/cert management, broken webmail configs. The result is a fragile system that breaks on every new domain and requires agent firefighting to keep working.
## Goal
Standard email service that works the same way for every self-hosted domain. When CyberPanel adds a domain, the email infrastructure is correct out of the box. No manual DNS overrides, no cross-domain SPF issues, no cert mismatches.
## Architecture
### DNS (per domain)
| Record | Name | Value | Notes |
| ——– | —— | ——- | ——- |
| A | `mail.<domain>` | 49.13.202.144 | IMAP/SMTP server |
| A | `webmail.<domain>` | 49.13.202.144 | Webmail interface |
| A | `smtp.<domain>` | 49.13.202.144 | Alias for mail (optional) |
| A | `imap.<domain>` | 49.13.202.144 | Alias for mail (optional) |
| MX | `<domain>` | `10 mail.<domain>` | Inbound delivery |
| TXT | `<domain>` | `v=spf1 mx a ip4:49.13.202.144 ~all` | SPF (authorizes our server via MX + IP) |
| TXT | `default._domainkey.<domain>` | (DKIM public key) | Generated by CyberPanel |
| TXT | `_dmarc.<domain>` | `v=DMARC1; p=quarantine; rua=mailto:[email protected];` | DMARC |
Key: SPF uses `mx` (which resolves to `mail.<domain>` → 49.13.202.144). This means the HELO domain and the sender domain both pass SPF alignment. No cross-domain issues.
### SSL/TLS (per domain)
| Cert | Covers | Purpose |
| —— | ——– | ——— |
| `mail.<domain>` | IMAP (993), SMTP (587/465) | Email client connections |
| `webmail.<domain>` | HTTPS (443) | Webmail interface |
Issued by: acme.sh DNS-01 (Cloudflare API) Stored in: `/etc/letsencrypt/live/mail.<domain>/` and `/etc/letsencrypt/live/webmail.<domain>/` SNI: Postfix `sni_maps` + Dovecot `local_name` blocks for each domain
### Mail Server
| Component | Role |
| ———– | —— |
| Postfix | MTA — receives inbound mail, delivers outbound |
| Dovecot | IMAP/POP3 — serves mailboxes to clients |
| OpenDKIM | Signs outbound email per-domain |
| Postfix SNI | Serves correct TLS cert per domain hostname |
| Dovecot SNI | Serves correct TLS cert per domain hostname |
Hostname: Postfix HELO = `mail.kaburu.cc` (canonical). Per-domain mail.* hostnames resolve to same IP. SNI ensures correct cert presentation.
### Webmail
Both clients access the same Dovecot mailbox:
| URL | Client |
| —– | ——– |
| `https://webmail.<domain>/snappymail/` | SnappyMail |
| `https://webmail.<domain>/roundcube/` | Roundcube |
Implementation: LiteSpeed vhost for `webmail.<domain>` with docRoot pointing to `/usr/local/CyberCP/public`. Both SnappyMail and Roundcube installed there. Rewrite rule redirects `/` → `/snappymail/` by default.
### Mailbox Storage
| Path | Format |
| —— | ——– |
| `/home/vmail/<domain>/<user>/Maildir/` | Dovecot Maildir |
Ownership: `vmail:vmail` (uid/gid 5000)
## Domain Types
| Type | MX Points To | Local Mailboxes | Use Case |
| —— | ————– | —————– | ———- |
| Self-hosted | `mail.<domain>` → 49.13.202.144 | Yes | touchwell, claybusters, friendscic, longniddry, chippyvan, rainbowvapes |
| External provider | Provider's MX (MS365, Google, Zoho, Proton) | No | dm-ph, jafricasafari, l8waterhygiene, myretonmarquees, etc. |
| Forward-only | `mail.<domain>` → 49.13.202.144 | No (virtual map only) | doctorfin, pilates-edinburgh |
Decision rule: If the client wants their own mailboxes → self-hosted. If they use MS365/Google/etc → external provider. If they just need forwarding to another address → forward-only.
## Adding a New Domain (Checklist)
### Self-hosted email
1. CyberPanel: Create website (if not exists) 2. CyberPanel: Create mailbox(es) 3. DNS (Cloudflare):
- Verify `mail.<domain>` A → 49.13.202.144
- Verify `webmail.<domain>` A → 49.13.202.144
- Verify MX → `10 mail.<domain>`
- Verify SPF: `v=spf1 mx a ip4:49.13.202.144 ~all`
- Verify DKIM: `default._domainkey.<domain>` TXT record
- Verify DMARC: `_dmarc.<domain>` TXT record
4. SSL: Issue certs for `mail.<domain>` and `webmail.<domain>` via acme.sh DNS-01 5. Postfix SNI: Add PEM entry to `/etc/postfix/sni_maps`, rebuild with `postmap -F` 6. Dovecot SNI: Add `local_name mail.<domain>` block to Dovecot config 7. LiteSpeed: Add vhost for `webmail.<domain>` (copy from template) 8. SnappyMail: Add domain config JSON in `/usr/local/CyberCP/public/snappymail/data/_data_/_default_/domains/` 9. Roundcube: Verify domain config exists (or create) 10. Postfix virtual map: Add forwarders if needed (e.g., `hello@` → external address) 11. Test: Send/receive email, verify DKIM signing, check webmail access
### External provider (MS365, Google, Zoho, Proton)
1. DNS: Point MX to provider's servers 2. DNS: Add provider's SPF include (e.g., `include:spf.protection.outlook.com`) 3. DNS: Add provider's DKIM records (if applicable) 4. DNS: Remove local mail.* A records (or leave them — harmless) 5. Verify: Test delivery to/from provider
### Forward-only
1. DNS: `mail.<domain>` A → 49.13.202.144 (if MX points to us) 2. Postfix virtual map: Add forwarder entries 3. No mailboxes, no webmail, no certs needed
## Retrofit Plan (Existing Domains)
Goal: Make all 8 self-hosted domains follow the standard architecture with minimal downtime.
Approach: One domain at a time. Each change is independent and reversible.
### Per-domain steps
1. Audit: Check current DNS, certs, SNI, DKIM, webmail config against spec 2. DNS: Add/update `mail.<domain>` and `webmail.<domain>` A records if missing 3. DNS: Update MX to `10 mail.<domain>` (from `mail.kaburu.cc`) 4. DNS: Update SPF to use `mx` instead of raw IP 5. SSL: Issue certs if missing 6. SNI: Add to Postfix/Dovecot if missing 7. Webmail: Add LiteSpeed vhost + SnappyMail config if missing 8. Test: Verify IMAP/SMTP/webmail still works 9. Monitor: Watch Postfix logs for bounces for 24h
Downtime: Near zero if done in order — DNS changes propagate, but existing IMAP/SMTP connections use `mail.kaburu.cc` which continues to work. MX change only affects new inbound mail (seconds of propagation).
### Domain order (safest first)
1. `rainbowvapes.co.uk` — just set up, minimal users (James only) 2. `thechippyvan.co.uk` — single mailbox (van@) 3. `claybusters.scot` — small site, few users 4. `friendscic.org` — committee email, moderate use 5. `longniddrybowlingclub.com` — single redirect mailbox 6. `longniddrybowlingclub.co.uk` — most mailboxes, test after confidence is high 7. `touchwell.co.uk` — Steve's personal mailbox, high value, do last 8. `kaburu.cc` — system domain, do very last
### Risk mitigation
- Rollback: Each step is independently reversible (change DNS back, remove SNI entry, etc.) - Monitoring: Watch Postfix logs for delivery failures after each domain - Communication: Tell users before changing their domain (especially touchwell — Steve's blind, phone settings may need help) - Parallel paths: Old `mail.kaburu.cc` continues to work alongside new `mail.<domain>` — no forced migration
## Testing (Spare Domain)
Use a spare domain to validate the full flow before retrofitting:
1. Add domain to CyberPanel via UI 2. Observe what DNS records CyberPanel creates automatically 3. Check if certs are issued automatically 4. Check if SNI is configured automatically 5. Check if SnappyMail/Roundcube configs are created automatically 6. Create a mailbox 7. Test IMAP/SMTP/webmail 8. Verify SPF/DKIM/DMARC 9. Document what CyberPanel does vs what we need to do manually
## Open Questions
1. Does CyberPanel auto-create SnappyMail domain configs? (Likely no — we may need to script this) 2. Does CyberPanel auto-create Roundcube domain configs? (Need to check) 3. Does CyberPanel auto-issue certs for mail.* subdomains? (Need to check) 4. Can we script the SNI map rebuild? (Yes — `postmap -F` on the sni_maps file) 5. Should we add Roundcube alongside SnappyMail, or pick one? (User wants both)
## Related Pages
- email-configuration — Current email setup reference - dns-spf-audit — Domain audit from 2026-07-14 - cyberpanel — CyberPanel operations - kaburusvr — Server details
