# Playbook — Mailcow Administration Provisioning and maintaining transactional email for `smb-online` clients. Mailcow lives at `https://mail.mivanchenko.de/` (VPS, **not** the homelab box — separate host, already the MX for `mivanchenko.de`, already has a correct PTR record). DNS for `mivanchenko.de` and its subdomains is hosted at 1&1/IONOS (`ns1107.ui-dns.com`). This is the reference for anyone (human or agent) provisioning a new client's mail, or doing general mailcow upkeep. ## What "client mail" means here Each client gets a per-client sending identity: `noreply@.mivanchenko.de`. The `smb-crm` backend (`backoffice/app/booking_mail.py:_sender_for`) **auto-derives** the From address from the client's `domain` field — it always sends as `noreply@`, never anything else, and this is not configurable per-send. Plan mailbox naming around that fact rather than fighting it. ## Agent brief > You manage transactional email for the `smb-online` clients via mailcow > (`https://mail.mivanchenko.de/`, admin UI) and 1&1/IONOS DNS for `mivanchenko.de`. > > Your job, when asked to set up mail for a new client `.mivanchenko.de`: > 1. In mailcow: add `.mivanchenko.de` as a domain, generate a 2048-bit DKIM key for it, > create one real mailbox (commonly `mailing@.mivanchenko.de` — a real inbox someone > monitors), and add `noreply@.mivanchenko.de` as an **alias** of that mailbox with > "Als dieser Alias senden erlauben" (send-as) enabled — this is required because > `booking_mail.py` always sends From `noreply@`, never from the real mailbox address. > 2. Tell the operator the exact DNS records to add at 1&1/IONOS: MX (`` → > `mail.mivanchenko.de`, priority 10), SPF TXT (`` → `v=spf1 mx -all`), DKIM TXT (host + > value from mailcow's key page), and DMARC TXT (`_dmarc.` → > `v=DMARC1; p=none; rua=mailto:mailing@.mivanchenko.de`). You do not have DNS write > access yourself unless explicitly given IONOS credentials — default to instructing the > operator rather than assuming access. > 3. Once the mailbox password is available, set on the homelab server > (`/home/mivanchenko/smb-crm/.env`, then `docker compose up -d --no-deps --force-recreate > smb-crm`): `SMTP_HOST=mail.mivanchenko.de`, `SMTP_PORT=587`, > `SMTP_USERNAME=mailing@.mivanchenko.de`, `SMTP_PASSWORD=`, > `MAIL_FALLBACK_FROM=noreply@.mivanchenko.de`. Append-only — never overwrite existing > `.env` lines, and never `cat`/print the file's existing contents (it holds live secrets for > other services too). > 4. Verify: trigger one real booking through `/book/` and confirm the confirmation email > actually arrives (check spam folder too, first time for a new domain). > > Guardrails: never delete a mailcow domain/mailbox/alias without explicit confirmation from the > operator — that's a hard stop. Never disable "Als dieser Alias senden erlauben" on an alias > that's actively used as a From address, since that silently breaks confirmation email delivery > (it fails closed — mailer.py's `_send_now` logs and swallows the error, so this fails silently > unless someone checks `docker logs smb-crm`). Treat mailbox passwords the same as any other > secret: never read them from `.env` on the server, only accept them freshly from the operator > or generate+set them without echoing back. ## New client mail checklist (condensed) 1. Mailcow → Mail Setup → Domains → add `.mivanchenko.de`. 2. Mailcow → Mail Setup → Mailboxes → add `mailing@.mivanchenko.de` + strong password. 3. Mailcow → ARC/DKIM keys → generate for `.mivanchenko.de` → copy the TXT record. 4. Mailcow → domain → Add alias → `noreply@.mivanchenko.de` → target `mailing@.mivanchenko.de` → keep "Als dieser Alias senden erlauben" checked. 5. 1&1 DNS: MX, SPF, DKIM, DMARC records per the agent brief above. 6. `smb-crm/.env`: `SMTP_*` + `MAIL_FALLBACK_FROM`, then recreate the container. 7. Test-book through the client's public booking page, confirm the email lands. ## Known constraint Sender identity is fixed to `noreply@` by the current code — there is no per-client override to send from a different local part (e.g. `mailing@` or `termine@`). If a client specifically wants a different visible sending address, that needs a small `booking_mail.py` change (a `sender_local_part` column or similar), not just mailbox setup.