Mail-Quotas mit Dovecot
Will man die Speicherbelegung durch die Mailaccounts beschränken, oder auch nur den Überblick über den Verbrauch behalten, so bietet sich das Quota-Plugin von Dovecot an.
Für die folgende Beschreibung habe ich nicht die Datei /etc/dovecot/conf.d/90-quota.conf erweitert, sondern meine lokale Konfigurationsdatei /etc/dovecot/local.conf. Dazu habe ich Ergänzungen an der Datei vorgenommen und zusätzlich noch ein paar weitere Dateien erstellt, deren Dateinamen sich aus der Erweiterung der Konfiguration ergeben.
/etc/dovecot/local.conf
Am Anfang der Datei habe ich folgende Zeile ergänzt:
mail_plugins = $mail_plugins quota
Damit wird das Quota-Plugin zusätzlich aktiviert.
Im Bereich für das Imap-Protokoll erfolgt dann noch die spezifische Einbindung für das Plugin imap_quota, das einem Imap-Client die Quota-Werte zustellen kann und keine weitere Konfiguration benötigt.
protocol imap { mail_max_userip_connections = 8 mail_plugins = $mail_plugins imap_quota }
Dann habe ich folgende Zeilen ergänzt, die genaue Position sollte keine Rolle spielen:
dict { sqluserquota = mysql:/etc/dovecot/dovecot-dict-sql-user.conf } plugin { #quota_rule = *:storage=1G #quota_rule2 = Trash:storage=+100M quota_grace = 10%% quota_warning = storage=66%% quota-warning 66 %u quota_warning2 = storage=80%% quota-warning 80 %u quota_warning3 = storage=95%% quota-warning 95 %u # quota = maildir:User quota:noenforcing quota = dict:User Quota::noenforcing:proxy::sqluserquota } service quota-warning { executable = script /usr/local/bin/quota-warning.sh user = vmail unix_listener quota-warning { group = vmail mode = 0660 user = vmail } } service dict { unix_listener dict { mode = 0600 user = vmail } }
Die Zeilen der Art
#quota_rule = *:storage=1G #quota_rule2 = Trash:storage=+100M quota_grace = 10%%
die Quota-Rules beschreiben die gültigen Speicherplatzbeschränkungen. Es kann mehrere Regeln geben, die dann am Ende durchnummeriert werden. Hier sind diese Regeln auskommentiert, sie werden ja jeweils aus der Datenbank bezogen. Gültig ist nur die quota_grace, die ein einmaliges Überschreiten des Grenzwertes erlaubt. Dadurch soll mit der letzten Mail die Grenze möglichst ausgeschöpft werden. So kann man vermeiden, dass große Mails schon abgelehnt werden, kleinere aber noch durchkommen, was den Nutzer verwirren könnte.
Mit den Zeilen
# quota = maildir:User quota:noenforcing quota = dict:User Quota::noenforcing:proxy::sqluserquota
wird das Quota-Backend beschrieben. Die auskommentierte Zeile würde den aktuellen Verbrauch im Dateisystem speichern und zwar in einer Datei maildirsize im Mail-Verzeichnis des jeweiligen Benutzers. Ich habe diese Version nicht weiter verfolgt, da Postfixadmin auf diese Informationen nicht zugreifen kann. Postfixadmin benötigt die Speicherung in einer bestimmten Datenbank-Tabelle. Dazu benötigt man eine Quota-Root vom Typ dict, über die auf die Datenbank zugegriffen werden kann.
Der frei festlegbare Bezeichner sqluserquota verweist auf die dict-Konfiguration am Anfang des neuen Bereiches. Hier ist dann die Datei angegeben, die die Kommunikation mit der Datenbank beschreibt, hier die Datei /etc/dovecot/dovecot-dict-sql-user.conf.
Generell gilt folgende Syntax für die Backend Definition
quota = dict:<quota root name>:<username>[:<option>[...]]:<dictionary URI>
Wenn das Feld Benutzername leer bleibt, dann wird der aktuelle Benutzer genommen, es ginge auch %d für Domainquotas. Die übliche Syntax ist also
quota = dict:<quota root name>:[:<option>[...]]:<dictionary URI>
Der zweite doppelte Doppelpunkt ergibt sich aus der Syntax-Regel für proxy
proxy:[<dict path>]:<destination dict>
und der Tatsache, dass der Pfad in der Regel nicht angegeben wird (siehe auch http://wiki2.dovecot.org/Dictionary ).
Für die dict-Konfiguration muss auch ein Service definiert werden, vor allem der zugehörige Benutzer. Über diesen Service wird dann kommuniziert. Für jeden definierten Service findet sich dann eine entsprechende Datei in /var/run/dovecot/.
Der Parameter noenforcing in der Backend-Definition bewirkt, dass die Quotas berechnet werden, aber keine Sperrung erfolgt, Mails werden auch über die konfigurierte Grenze hinaus angenommen.
Aber Warnungen werden generiert, dazu dienen die Zeilen:
quota_warning = storage=66%% quota-warning 66 %u quota_warning2 = storage=80%% quota-warning 80 %u quota_warning3 = storage=95%% quota-warning 95 %u
Beim Überschreiten der jeweiligen Grenzen bekommt der Benutzer eine entsprechende Meldung. Auch dies ist wieder über einen Service geregelt, nämlich quota-warning. Es wird dort das angegebene Script /usr/local/bin/quota-warning.sh mit den Parametern Auslastung in % und Postfach aufgerufen, also z.B.
/usr/local/bin/quota-warning.sh 80 test@netthelp.de
Mit dem direkten Aufruf kann man das Script auch testen.
dovecot-mysql.conf
# Database driver: mysql, pgsql driver = mysql # Currently supported schemes include PLAIN, PLAIN-MD5, DIGEST-MD5, and CRYPT. default_pass_scheme = CRYPT # Database options #db_unix_socket = /var/lib/mysql/mysql.sock connect = host=/var/run/mysql/mysql.sock dbname=postfix user=postfix password=assword password_query = SELECT password FROM mailbox WHERE username = '%u' AND active = '1' user_query = SELECT concat('maildir:/var/vmail/',maildir) as mail, \ 303 AS uid, \ 303 AS gid, \ CONCAT('*:bytes=', \ IF(mailbox.quota = 0, domain.maxquota*1024000, mailbox.quota)) \ as quota_rule \ FROM mailbox, domain \ WHERE username = '%u' AND mailbox.active = '1' AND \ domain.domain = '%d' AND domain.active = '1' iterate_query = SELECT username as user FROM mailbox WHERE active ='1'
Gegenüber der ursprünglichen Version ist hier die user_query erweitert, so dass auch die Quotas abgefragt werden. Die Logik ist recht aufwendig gestaltet. Wenn für einen Benutzer keine Quotas angegeben sind, also der Wert auf 0 steht, dann wird der Wert maxquota aus der Domaintabelle benutzt.
Zusätzlich habe ich noch die iterate_query eingeführt, die benötigt man, wenn man z.B. mittels
doveadm quota recalc -u *@netthelp.de
die Belegung für alle Benutzer der angegebenen Domain erneut berechnen will, oder sie für alle Benutzer mittels
doveadm quota get -u *@netthelp.de
abfragen möchte.
Auch für die Neuberechnung aller Belegungen
doveadm quota recalc -A
oder deren Abfrage
doveadm quota get -A
braucht man die Iteration.
dovecot-dict-sql-user.conf
Diese Datei beschreibt welche Informationen Dovecot in welches Feld der Datenbank schreibt.
connect = host=/var/run/mysql/mysql.sock dbname=postfix user=postfix password=assword map { pattern = priv/quota/storage table = quota2 username_field = username value_field = bytes } map { pattern = priv/quota/messages table = quota2 username_field = username value_field = messages }
Die Daten kommen in die Tabelle quota2 und zwar der Speicherplatzbedarf in das Feld bytes und die Anzahl der Mail in das Feld messages, jeweils beim Benutzer username.
Hinweis: Hier gibt es eine große Gefahr. Dovecot löscht erst die Zeile für den Benutzer, bevor es sie neu einträgt. Wenn noch andere Daten in der gleichen Tabellenzeile stehen sind die damit eventuell verloren. Ich hatte eine entsprechendes Problem, als ich Domain-Quotas in die Tabelle domain eintragen lassen wollte. Bis ich das Problem erkannt hatte waren zwei Maildomains gelöscht.
Ich verzichte daher momentan auf die Nutzung von Domain-Quotas, obwohl man eventuell mit dem Parameter no-unset in der Backend-Definition dieses Verhalten unterbinden kann (ab Version 2.2.20 siehe http://wiki2.dovecot.org/Quota/Dict http://dovecot.2317879.n4.nabble.com/More-information-about-Dovecot-2-2-x-quota-mysql-and-dict-td54077.html http://code.metager.de/source/history/dovecot/2.2/)
/usr/local/bin/quota-warning.sh
Dieses Script erstellt die Warnmeldungen, wenn die angegebenen Auslastungswerte überschritten werden.
#!/bin/sh PERCENT=$1 USER=$2 ADMIN="verwalter@domain.de" FROM="postmaster@domain.de" msg="From: $FROM To: $USER Bcc: $ADMIN Subject: Quota-Warnung $PERCENT% Lieber Nutzer, das Postfach $USER ist derzeit zu $PERCENT% gefuellt. Bitte einige Mails loeschen. Herzlichen Dank Das Netthelp Mail-System." echo -e "$msg" | /usr/sbin/sendmail -t -f $FROM "$USER" exit 0
In vielen Beschreibungen findet man folgende Version für das Script:
#!/bin/sh PERCENT=$1 USER=$2 cat << EOF | /usr/lib/dovecot/dovecot-lda -d $USER -o "plugin/quota=maildir:User quota:noenforcing" From: postmaster@domain.com Subject: quota warning Your mailbox is now $PERCENT% full. EOF
Das bewirkt auf alle Fälle, dass zusätzlich im Verzeichnis des Benutzers die Auslastungsdatei erzeugt wird. Meiner Ansicht nach sollte hier nicht ein Maildir-Quota benutzt werden (denkbar -d $USER -o "plugin/quota=dict:User quota::noenforcing:proxy::sqluserquota" analog zu http://www.tech-island.com/tutorials/webserver/mail ). Diese Regel soll auf alle Fälle die Zustellung der Warnmeldung ermöglichen. Da ich aber nur Warnungen unterhalb von 100% erzeuge sollte das kein Problem sein.
/srv/www/htdocs/postfixadmin/config.inc.php
Damit sich die Quota-Konfiguration mit Postfixadmin verwalten lässt müssen in der Konfigurationsdatei ein paar Einstellungen angepasst werden.
$CONF['maxquota'] = '10240'; $CONF['domain_quota_default'] = '20480'; $CONF['quota'] = 'YES'; $CONF['used_quotas'] = 'YES'; $CONF['domain_quota'] = 'YES'; $CONF['quota_multiplier'] = '1024000'; $CONF['new_quota_table'] = 'YES';
Ablehnung durch Postfix, wenn Postfach voll
Für einen Benutzer, der seine Quotas überzogen hat soll möglichst schon Postfix die Mail gar nicht erst annehmen. Sonst müssen später bei der fehlgeschlagenen Zustellung Fehlermeldungen generiert und verschickt werden. Damit Postfix von Dovecot erfährt, dass das Postfach voll ist muss man die Konfiguration um einen weiteren Service ergänzen.
service quota-status { executable = quota-status -p postfix inet_listener { # address = 127.0.0.1 port = 12345 } client_limit = 1 }
Die Portnummer hier kann man nahezu beliebig wählen, sie muss nur frei sein.
Nun muss man die Meldungen konfigurieren:
plugin { quota_status_success = DUNNO quota_status_nouser = DUNNO quota_status_overquota = "552 5.2.2 Mailbox is over quota / Mailbox ist voll" }
Wenn der Benutzer über seinem Limit liegt, dann kommt eine Fehlermeldung zurück, ansonsten DUNNO, was soviel bedeutet wie "noch keine Entscheidung getroffen", dann muss Postfix anhand anderer Regeln ermitteln, ob die Mail angenommen wird.
Die Postfix-Konfiguration muss dann im Bereich
smtpd_recipient_restrictions =
erweitert werden um eine Zeile wie:
check_policy_service inet:127.0.0.1:12345,
Diesen Teil habe ich bisher noch nicht getestet, da ich momentan auch noch keine Mails ablehnen möchte.
Werkzeuge für Dovecot
doveadm who
zeigt an, wer mit welcher IP angemeldet ist
doveadm kick <user>
beendet die Verbindung des angegebenen Users.
doveadm search -u <user> mailbox Trash savedbefore 60d
Zeigt alle Mail im Ordner Trash, die vor mehr als 60 Tagen gespeichert wurden.
Vergleichsoperatoren können sein SAVEDBEFORE, SAVEDON, SAVEDSINCE , gültige Zeiteinheiten sind weeks (abbr: w), days (abbr: d), hours (abbr: h), mins (abbr: m) and secs (abbr: s).
doveadm expunge -u <user> mailbox Junk savedbefore 60d
Löscht alle Mail im Ordner Junk, die vor mehr als 60 Tagen gespeichert wurden.
Weitere Informationen unter http://wiki2.dovecot.org/Tools/Doveadm/SearchQuery , http://wiki2.dovecot.org/Tools/Doveadm/Search und https://wiki2.dovecot.org/Tools/Doveadm/Mailbox .
Statt für einen User kann man mit dem Parameter -A die Operationen auch für alle Nutzer ausführen. Das ist auch die Idee hinter folgendem kleinen Script:
#!/bin/bash # DOVEADM="/usr/bin/doveadm"; $DOVEADM expunge -A mailbox Trash savedbefore 90d $DOVEADM expunge -A mailbox Junk savedbefore 60d
doveadm mailbox list -u <user>
Zeigt die Imap-Ordner des angegebenen Benutzers:
Sent Drafts Trash Junk INBOX
Neue Ordner anlegen kann man mittels:
doveadm mailbox create -u <user> Papierkorb
Löschen kann man dann Ordner mittels:
doveadm mailbox delete -u <user> Papierkorb
Zu klären
Folgende Punkte sind aus meiner Sicht noch zu klären bzw. müssen ausprobiert werden:
- Abgleich der Quota-Warnungen mit den Farbwechseln (Gelb-Rot) bei PostfixAdmin (anscheinend bei 45% und 75%)
- Vermeiden des Löschens der MySQL-Domain bei Domainquotas mit dict
- Ablehnung der Mails durch Postfix