Seit v0.26.6 laufen alle System-Mails über einen zentralen Helfer (send_branded_mail() in apps/core/emails.py). Begonnen hat es mit den vier Onboarding-Mails (v0.25.4). Jeder Versand steht seit v0.28.32 im Mailprotokoll des Cockpits.
22 Mailtypen, ein Erscheinungsbild:
Aufbau: Logo-Kopf, Überschrift, Absätze, Detail-Tabelle (Label/Wert), grosser Code, Hauptknopf plus optionaler zweiter Knopf, Schlussabsätze, Kontaktblock, dunkler Fuss. Jede Mail hat einen Text-Fallback aus denselben Bausteinen.
Absender und Antwort-an: Plattform-Mails kommen von «CluHu» und verweisen auf info@cluhu.ch. Vereins-Mails zeigen « via CluHu» als Absendername, die Fusszeile «Diese E-Mail wurde von über CluHu versendet.» und die Kontaktzeile «Bei Fragen wende dich an — ». Antwort-an ist die Kontaktadresse aus dem Vereinsprofil, falls gesetzt.
Bilder per CID (v0.25.5): Logo und Doppelwelle stecken als PNG in der Mail. Outlook zeigt sie sofort, ohne «Bilder herunterladen».
Wegwerf-Mail-Sperre (v0.25.4): Registrierung und E-Mail-Änderung im Onboarding lehnen Wegwerf-Domains ab (rund 8700 Domains aus einer öffentlichen Liste plus eigene Ergänzungsdatei). Die Meldung erklärt, wofür die Adresse gebraucht wird.
Mailsperre für Testadressen (v0.28.42): An Adressen auf *.cluhu.test geht nie eine Mail, in keinem Mandanten. Ein eigenes Mail-Backend entfernt solche Empfänger vor dem Versand. Bleibt niemand übrig, wird die Mail still verworfen und als gesendet gezählt; «Einladung senden» oder «Rechnung zustellen» zeigen keinen Fehler. Die Adressen bleiben formal gültig und lassen sich in der Oberfläche eingeben. Alle Testmandanten sind seit 14.10.2026 so maskiert (siehe Migration Musikverein Spiez).
send_branded_mail() und Djangos send_mail() und greift so auch für Cron-Jobs und den Passwort-Reset. Eine Prüfung je Code-Pfad wäre beim nächsten Mailtyp vergessen gegangen.Eigene Absenderdomain je Verein, Vereinslogo im Mailkopf, vom Verein gestaltbare Vorlagen (nur der Rechnungsmail-Text ist konfigurierbar), Mail-Queue mit Wiederholung (Versand bleibt synchron).
Wegwerf-Container mit Worktree-Code und locmem-Backend; ein Script spielt alle Pfade mit testverein-Daten in einer Transaktion durch und rollt zurück; HTML-Dumps per Headless-Chromium rendern. Danach je ein Exemplar aus dem Live-Container an eine eigene Adresse schicken. Das Onboarding-Setup legt media/clubs/<uuid> an, nachher löschen. Nach dem Merge restart web. E-Mail ist auf dem Live-Stack ECHTES SMTP: Tests und Seeds nur mit locmem.
⚠️ Das Sperr-Backend ist in config/settings/dev.py eingetragen; der Live-Stack läuft mit diesen Settings. prod.py kennt es nicht. Wäre prod je aktiv, gingen Mails an *.cluhu.test ungehindert raus.
⚠️ Unterdrückte Testmails stehen im Mailprotokoll als gesendet.