Mail-Hygiene: Inaktive E-Mail-Konten in Froxlor finden   Vor kurzem aktualisiert!


Wer einen eigenen Mailserver betreibt, kennt das Problem: Über die Jahre sammeln sich E-Mail-Adressen an. Projekt-Postfächer, die nicht mehr genutzt werden, Konten von ehemaligen Nutzenden oder einfach „Leichen“, die man beim letzten Serverumzug mitgeschleppt hat.

Warum sollte man diese Konten überhaupt löschen? Es geht um weit mehr als nur ein paar Megabyte Speicherplatz.

Warum „Aufräumen“ eine Sicherheitsmaßnahme ist

Ein sauberes System ist ein sicheres System. Inaktive E-Mail-Konten bergen verschiedene Risiken:

  • Sicherheitsrisiko: Jedes existierende Konto ist ein potenzielles Einfallstor für Brute-Force-Angriffe. Ein Konto, das niemand aktiv nutzt, wird oft nicht auf verdächtige Aktivitäten überwacht.
  • Speicherplatz & Backup-Effizienz: Auch wenn Textnachrichten klein sind, blähen jahrelang gesammelte Anhänge die Backups unnötig auf. Kürzere Backup-Zeiten und weniger Speicherbedarf sind sehr sinvolle Ziele.
  • Datenschutz (DSGVO): Nach dem Prinzip der Datensparsamkeit sollten Konten, die keinen Zweck mehr erfüllen, gelöscht werden.
  • Reputation des Mailservers: Falls ein altes Konto gehackt und für Spam missbraucht wird, landet die IP deines Servers schnell auf Blacklists.

Das Analyse-Skript: Login-Check über alle Logfiles

Das folgende Bash-Skript automatisiert die Suche. Es liest alle E-Mail-Adressen aus der Froxlor-Datenbank aus und durchsucht die Mail-Logs (/var/log/mail.log) inklusive der rotierten und komprimierten Archive (.gz). So erfährt man auf einen Blick, wer sich im letzten Monat (oder solange die Logs zurückreichen) eingeloggt hat.

Das Skript

#!/bin/bash

# Konfiguration
LISTE="/tmp/email-lastlogin.txt"
LOGS="/var/log/mail.log*"

# --- 1. Zeitraum-Analyse über ALLE Dateien ---
# Wir suchen die älteste Datei (höchste Nummer) für den Startzeitpunkt
OLDEST_LOG=$(ls -1 /var/log/mail.log.*.gz 2>/dev/null | sort -V | tail -n 1)
CURRENT_LOG="/var/log/mail.log"

# Falls keine alten Logs da sind, nehmen wir das aktuelle
if [ -z "$OLDEST_LOG" ]; then OLDEST_LOG=$CURRENT_LOG; fi

START_DATE=$(zgrep . "$OLDEST_LOG" | head -n 1 | cut -c 1-15)
END_DATE=$(tail -n 1 "$CURRENT_LOG" | cut -c 1-15)

echo "============================================================================="
echo "MAIL-LOGIN ANALYSE"
echo "Zeitraum: $START_DATE bis $END_DATE"
echo "============================================================================="

# --- 2. E-Mail-Liste aus Froxlor holen ---
echo "Hole E-Mail-Liste aus der Froxlor-Datenbank..."
# Hinweis: Das Passwort wird interaktiv abgefragt
mysql -u root -p -e "SELECT email FROM froxlor.mail_users;" --batch --skip-column-names > "$LISTE"
echo "-----------------------------------------------------------------------------"

# --- 3. Abgleich mit den Logs ---
echo "Prüfung der letzten Logins (bitte Geduld)..."
echo ""

while read -r email; do
    [[ -z "$email" || "$email" == "email" ]] && continue

    # zgrep durchsucht Text und Gzip-Archive gleichzeitig
    # -i: ignoriert Groß/Kleinschreibung, -h: unterdrückt Dateinamen-Ausgabe
    LAST_LOGIN=$(zgrep -ih "$email" $LOGS | grep -i "Login" | tail -n 1)

    if [ -z "$LAST_LOGIN" ]; then
        echo "[ ] $email: KEIN LOGIN im Zeitraum gefunden."
    else
        # Extrahiert das Datum (ersten 15 Zeichen)
        DATE=$(echo "$LAST_LOGIN" | cut -c 1-15)
        echo "[X] $email: Letzter Login am $DATE"
    fi
done < "$LISTE"

echo "-----------------------------------------------------------------------------"
echo "Analyse abgeschlossen."

Wie man das Skript nutzt

  1. Speichern: Kopiere den Code in eine Datei, z.B. check_mail_logins.sh.
  2. Rechte vergeben: Mache das Skript ausführbar: chmod +x check_mail_logins.sh.
  3. Ausführen: Starte es mit sudo ./check_mail_logins.sh. Du wirst nach deinem MySQL-Root-Passwort gefragt.

Wie geht man mit dem Ergebnis um?

Adressen, die mit [ ] markiert sind, haben sich im gesamten Log-Zeitraum nicht eingeloggt. Das ist die „To-Do-Liste“. Vor dem Löschen, empfiehlt es sich, die entsprechenden Nutzer zu kontaktieren oder das Postfach zunächst nur für den Login zu sperren, und die Löschung der Daten (E-Mails im Postfach) für einen späteren Zeitpunkt zu avisieren.

Automatisierung über Cron

Um das Skript in einem Cronjob zu nutzen oder einfach den Komfort zu erhöhen, empfiehlt es sich, die MySQL-Zugangsdaten in eine separate Datei auszulagern. Wir nutzen dafür das Standardformat der .my.cnf, auf die nur der Root-Benutzer Zugriff haben sollte.

Vorbereitung

Man erstellt beispielsweise eine Datei /root/.froxlor_db.cnf, mit folgendem Inhalt:

[client]
user=root
password=DEIN_PASSWORT

Und sichert die Datei ab: chmod 600 /root/.froxlor_db.cnf

Das erweiterte Skript für die Nutzung mit Cron

#!/bin/bash

# --- KONFIGURATION ---
# Pfad zur Datei mit den MySQL-Zugangsdaten (Sicherheit!)
DB_CONFIG="/root/.froxlor_db.cnf"
LISTE="/tmp/email-lastlogin.txt"
LOGS="/var/log/mail.log*"

# Überprüfung, ob die Config-Datei existiert
if [ ! -f "$DB_CONFIG" ]; then
    echo "Fehler: $DB_CONFIG nicht gefunden! Bitte erstellen für automatischen Login."
    exit 1
fi

# --- 1. ZEITRAUM-ANALYSE ---
# Höchste Nummer der .gz Archive finden (älteste Daten)
OLDEST_LOG=$(ls -1 /var/log/mail.log.*.gz 2>/dev/null | sort -V | tail -n 1)
CURRENT_LOG="/var/log/mail.log"

# Falls keine Archiv-Logs vorhanden sind, nur das aktuelle nutzen
[[ -z "$OLDEST_LOG" ]] && OLDEST_LOG=$CURRENT_LOG

START_DATE=$(zgrep . "$OLDEST_LOG" | head -n 1 | cut -c 1-15)
END_DATE=$(tail -n 1 "$CURRENT_LOG" | cut -c 1-15)

echo "============================================================================="
echo "MAIL-LOGIN ANALYSE FÜR FROXLOR"
echo "Zeitraum: $START_DATE bis $END_DATE"
echo "============================================================================="

# --- 2. E-MAIL-LISTE AUS DB EXTRAHIEREN ---
echo "Extrahiere aktive Konten aus Froxlor..."
# Nutzt die --defaults-extra-file Option für passwortlosen Login
mysql --defaults-extra-file="$DB_CONFIG" -e "SELECT email FROM froxlor.mail_users;" --batch --skip-column-names > "$LISTE"
echo "Erfolgreich eingelesen."
echo "-----------------------------------------------------------------------------"

# --- 3. LOG-CHECK ---
echo "Prüfung läuft (dies durchsucht auch komprimierte Archive)..."
echo ""

while read -r email; do
    # Überspringe leere Zeilen
    [[ -z "$email" ]] && continue

    # Suche nach dem aktuellsten Login-Zeitstempel
    # -i: Case-insensitive, -h: Dateinamen in der Ausgabe unterdrücken
    LAST_LOGIN=$(zgrep -ih "$email" $LOGS | grep -i "Login" | tail -n 1)

    if [ -z "$LAST_LOGIN" ]; then
        echo "[ ] $email: KEIN LOGIN gefunden (seit $START_DATE)"
    else
        # Datum aus dem Log-String extrahieren
        DATE=$(echo "$LAST_LOGIN" | cut -c 1-15)
        echo "[X] $email: Letzter Login am $DATE"
    fi
done < "$LISTE"

echo "-----------------------------------------------------------------------------"
echo "Analyse abgeschlossen. Ergebnisse unter $LISTE gespeichert."

Vorteile dieser Lösung:

  1. Automatisierung: Man kann das Skript jetzt als Cronjob laufen lassen, ohne dass es bei der Passwortabfrage stehen bleibt (z.b. Falls man daraus ein separates Log oder eine Informatione-E-Mail erstellen will).
  2. Sicherheit: Passwörter stehen nicht im Klartext im Skript (wo sie jeder mit Leserechten sehen könnte), sondern in einer geschützten Systemdatei.
  3. Fehlertoleranz: Das Skript prüft nun, ob überhaupt Log-Archive existieren, bevor es versucht, das Startdatum zu lesen.

Weitere Ideen

Man kann die Liste /tmp/email_lastlogin.txt auch mit grep "[ ]" filtern, um sofort eine Liste aller „toten“ Konten zu erhalten, die man dann weiter bearbeiten kann.


„Mail-Audit“ Skript (mit HTML-Export)

#!/bin/bash

# --- KONFIGURATION ---
DB_CONFIG="/root/.froxlor_db.cnf"
LISTE="/tmp/email_lastlogin.txt"
HTML_OUT="/var/www/html/mail_audit.html" # Pfad zu deinem Web-Ordner
LOGS="/var/log/mail.log*"

# Überprüfung der Config-Datei
if [ ! -f "$DB_CONFIG" ]; then
    echo "Fehler: $DB_CONFIG nicht gefunden!"
    exit 1
fi

# --- 1. ZEITRAUM-ANALYSE ---
OLDEST_LOG=$(ls -1 /var/log/mail.log.*.gz 2>/dev/null | sort -V | tail -n 1)
CURRENT_LOG="/var/log/mail.log"
[[ -z "$OLDEST_LOG" ]] && OLDEST_LOG=$CURRENT_LOG

START_DATE=$(zgrep . "$OLDEST_LOG" | head -n 1 | cut -c 1-15)
END_DATE=$(tail -n 1 "$CURRENT_LOG" | cut -c 1-15)

# --- 2. HTML HEADER ERSTELLEN ---
cat <<EOF > "$HTML_OUT"
<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <title>Mail-Audit: Froxlor Login-Check</title>
    <style>
        body { font-family: sans-serif; margin: 40px; background: #f4f4f9; }
        table { width: 100%; border-collapse: collapse; background: white; box-shadow: 0 2px 5px rgba(0,0,0,0.1); }
        th, td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }
        th { background-color: #005f87; color: white; }
        tr:hover { background-color: #f1f1f1; }
        .active { color: #27ae60; font-weight: bold; }
        .inactive { color: #c0392b; font-weight: bold; }
        .header-info { margin-bottom: 20px; padding: 15px; background: #e8eff2; border-left: 5px solid #005f87; }
    </style>
</head>
<body>
    <h1>E-Mail Konto Analyse</h1>
    <div class="header-info">
        <strong>Analyse-Zeitraum:</strong> $START_DATE bis $END_DATE <br>
        <strong>Geprüfte Logs:</strong> $LOGS
    </div>
    <table>
        <tr>
            <th>Status</th>
            <th>E-Mail Adresse</th>
            <th>Letzter Login</th>
        </tr>
EOF

# --- 3. DATEN VERARBEITEN ---
echo "Extrahiere Daten und erstelle HTML..."
mysql --defaults-extra-file="$DB_CONFIG" -e "SELECT email FROM froxlor.mail_users;" --batch --skip-column-names > "$LISTE"

while read -r email; do
    [[ -z "$email" ]] && continue

    LAST_LOGIN=$(zgrep -ih "$email" $LOGS | grep -i "Login" | tail -n 1)

    if [ -z "$LAST_LOGIN" ]; then
        echo "<tr><td class='inactive'>[ INAKTIV ]</td><td>$email</td><td>Kein Login gefunden</td></tr>" >> "$HTML_OUT"
    else
        DATE=$(echo "$LAST_LOGIN" | cut -c 1-15)
        echo "<tr><td class='active'>[ AKTIV ]</td><td>$email</td><td>$DATE</td></tr>" >> "$HTML_OUT"
    fi
done < "$LISTE"

# --- 4. HTML ABSCHLIESSEN ---
echo "    </table>
    <p><small>Generiert am: $(date)</small></p>
</body>
</html>" >> "$HTML_OUT"

echo "Fertig! Die Analyse ist unter $HTML_OUT verfügbar."

Versand per E-Mail

Vollautomatisch: Den Bericht monatlich im Postfach

Durch die Kombination aus dem Skript und einem Cronjob erhält man einmal im Monat eine übersichtliche E-Mail.

Da die HTML-Header direkt mitgesendet werden, erscheint der Bericht direkt als formatierte Tabelle im E-Mail-Programm.

Um das Skript so zu erweitern, dass es die HTML-Ausgabe direkt per E-Mail versendet, nutzt man am besten das Tool mutt oder mailx. Da eine HTML-E-Mail spezielle Header benötigt, damit sie im Mail-Client (Thunderbird, Gmail,..) auch als formatierte Tabelle und nicht als Quellcode angezeigt wird, passen wir das Ende des Skripts an.

Mail-Tool installieren

sudo apt-get install bsd-mailx

Ergänzung (Versand-Logik)

Dieser Block wird am Ende des bestehenden Skripts eingebaut und arbeitet dann denMailversand ab (nachdem die HTML-Datei fertig geschrieben wurde):

# --- 5. E-MAIL VERSAND ---
EMPFAENGER="deine-email@beispiel.de"
BETREFF="Monatlicher Mail-Audit: Froxlor Login-Bericht ($(date +%m/%Y))"

echo "Sende HTML-Bericht an $EMPFAENGER..."

# Versand als HTML-E-Mail
# Wir nutzen 'mail' mit dem Header für HTML-Content
(
  echo "Subject: $BETREFF"
  echo "MIME-Version: 1.0"
  echo "Content-Type: text/html; charset=utf-8"
  echo "To: $EMPFAENGER"
  echo ""
  cat "$HTML_OUT"
) | /usr/sbin/sendmail -t

echo "E-Mail wurde versendet."

Automatisierung per Cronjob

Damit man sich nicht persönlich darum kümmern muss, richten wir einen Cronjob ein. Dieser sorgt dafür, dass das Skript automatisch am 1. jedes Monats um Mitternacht ausgeführt wird.

  1. Crontab öffnen als Root: sudo crontab -e
  2. Ganz unten folgende Zeile hinzufügen (Pfade ggf. anpassen):
    0 0 1 * * /pfad/zu/deinem/skript.sh > /dev/null 2>&1
    • 0 0 = 00:00 Uhr
    • 1 = am 1. Tag des Monats
    • * * = jeden Monat, jeden Wochentag

Regelmäßige Bereinigungen können auf diesem Weg zu einem festen Bestandteil der Server-Hygiene werden. Die visuelle Aufbereitung der Daten bietet eine praktische Entscheidungsgrundlage, bevor endgültige Löschungen vorgenommen werden.