
Automate Dovecot Mailbox Quota Reports with a Shell Script
Before you run this
This guide builds a small shell script that runs doveadm quota get for every mailbox on a Dovecot server, writes a plain-text usage report to a file, and emails you a summary that flags anyone at or above a threshold (90% by default). It is a read-only reporting script. It queries quota figures that Dovecot already tracks; it does not create, resize, recalculate, or delete anything in a mailbox.
A few things to be honest about up front:
- It needs root.
doveadmreads Dovecot's configuration and every user's quota through the master process, so run it asroot(or viasudo). An unprivileged user will get permission errors or an empty list. - The only things that persist are harmless: a report file under a log directory you choose, and a cron entry. Neither touches mail data.
- Test it first. Read the script before you run it. Run it by hand on one server and eyeball the output — column order and units in
doveadmoutput can differ between Dovecot versions, so confirm the report matches reality before you trust a nightly email. If you want to be extra careful, test the parsing against a single user withdoveadm quota get -u testuser@example.comfirst. - The only Dovecot command in this guide that changes state is
doveadm quota recalc, which I mention at the end but do not put in the script. Don't add it to a scheduled job casually.
Assumptions for this guide: Debian 12 or Ubuntu 22.04, Dovecot installed from the distribution packages with the quota plugin already configured and working, bash, and a working local MTA (Postfix) plus the mail command from the mailutils package for delivery. On RHEL/AlmaLinux the logic is identical; the mail-sending package is mailx and paths may differ.
Confirm the building block works
Before scripting anything, prove the underlying command works on your box:
sudo doveadm quota get -u someuser@example.com
You should get a small table: Quota name, Type, Value, Limit, %. The STORAGE row is the one we care about. If this errors out, the quota plugin isn't configured and the script has nothing to report — fix that first (see the doveadm-quota(1) man page and the quota configuration section of the Dovecot documentation at doc.dovecot.org).
Now the whole-server version. The -A flag iterates every user in the userdb, and -f tab gives clean tab-separated output that's easy to parse:
sudo doveadm -f tab quota get -A
With -A, Dovecot prepends a Username column, so the fields are: Username, Quota name, Type, Value, Limit, %. Run it once and confirm that order on your version — if it differs, adjust the field numbers in the script below.
The script
Save this as /usr/local/sbin/dovecot-quota-report.sh and make it executable. Replace the three obvious placeholders at the top: the report directory, the threshold, and the recipient address.
#!/usr/bin/env bash
set -euo pipefail
# ---- settings you replace ----
REPORT_DIR="/var/log/dovecot-quota" # where reports are written; change to taste
THRESHOLD=90 # flag mailboxes at/above this % of STORAGE quota
MAILTO="admin@example.com" # who receives the summary; replace
# ------------------------------
HOST_FQDN="$(hostname -f)"
TODAY="$(date +%Y-%m-%d)"
REPORT_FILE="${REPORT_DIR}/quota-${TODAY}.txt"
mkdir -p "$REPORT_DIR"
# Collect quota for all users, tab-separated so it's safe to parse.
raw="$(doveadm -f tab quota get -A)"
# Build the full report file. NR==1 skips the header row from doveadm.
{
echo "Dovecot mailbox quota report"
echo "Host: ${HOST_FQDN}"
echo "Date: ${TODAY}"
echo
printf "%-40s %12s %12s %6s\n" "User" "Used" "Limit" "Use%"
printf '%s\n' "$raw" | awk -F'\t' '
NR==1 { next }
$3 == "STORAGE" { printf "%-40s %12s %12s %6s\n", $1, $4, $5, $6 }
'
} > "$REPORT_FILE"
# Build the over-threshold list. Skip rows with no percentage (unlimited quota).
over="$(printf '%s\n' "$raw" | awk -F'\t' -v t="$THRESHOLD" '
NR==1 { next }
$3 == "STORAGE" && $6 != "" && $6 != "-" && ($6 + 0) >= t {
printf "%s (%s%%)\n", $1, $6
}')"
# Only send mail when there is something to flag.
if [ -n "$over" ]; then
{
echo "Mailboxes at or above ${THRESHOLD}% of their storage quota on ${HOST_FQDN}:"
echo
echo "$over"
echo
echo "----- full report -----"
cat "$REPORT_FILE"
} | mail -s "Dovecot quota report - ${HOST_FQDN} - ${TODAY}" "$MAILTO"
fi
echo "Report written to ${REPORT_FILE}"
Set permissions:
sudo chown root:root /usr/local/sbin/dovecot-quota-report.sh
sudo chmod 750 /usr/local/sbin/dovecot-quota-report.sh
A few notes on the non-obvious parts:
set -euo pipefailmakes the script stop on errors and on unset variables rather than sending you a half-built report.- The awk uses
$3 == "STORAGE"so message-count quota rows don't clutter the report. If you also want to report on theMESSAGEtype, add a second block — don't overload one line. ($6 + 0) >= tforces awk to treat the percentage as a number. Rows with an unlimited limit (percentage blank or-) are skipped so they don't trigger false alarms.- The units in the
Used/Limitcolumns are whateverdoveadmreports (typically kibibytes for storage). I label them plainly rather than converting, so nothing is silently wrong. Convert in awk later if you like, once you've confirmed the unit.
Run it once by hand
Do this before scheduling anything:
sudo /usr/local/sbin/dovecot-quota-report.sh
Check that /var/log/dovecot-quota/quota-YYYY-MM-DD.txt exists and looks right, and that if any mailbox is over the threshold you actually received the email. If you want to force an email during testing, temporarily lower THRESHOLD to something like 1.
Schedule it
Use a cron.d file so the schedule lives in one obvious place. Create /etc/cron.d/dovecot-quota-report:
# Dovecot quota report — runs 07:00 daily as root
0 7 * * * root /usr/local/sbin/dovecot-quota-report.sh >/dev/null 2>&1
Cron mails root any output on error; the >/dev/null 2>&1 keeps normal runs quiet while still letting a crash surface through cron's own mail. Adjust the time and frequency to taste — weekly (0 7 * * 1) is plenty for most servers.
Verify it worked
- The command:
sudo doveadm -f tab quota get -A | headshould show real data. - The report:
ls -l /var/log/dovecot-quota/and open the latest file. Spot-check one user againstdoveadm quota get -u thatuser@example.com— the numbers must match. - The schedule:
sudo systemctl status cron(Debian/Ubuntu; it'scrondon RHEL) confirms cron is running, and after the first scheduled run a fresh dated file should appear.
Undo
Nothing here modifies mailboxes, so rollback is just removing what you added:
sudo rm /etc/cron.d/dovecot-quota-report # stop the schedule
sudo rm /usr/local/sbin/dovecot-quota-report.sh # remove the script
sudo rm -r /var/log/dovecot-quota # remove accumulated reports
If a user's reported usage looks obviously wrong (say, after moving mail on disk), Dovecot can recompute it with doveadm quota recalc -u user@example.com. That changes stored quota state, so run it deliberately per user and never bury it in this reporting script. See the doveadm-quota(1) man page for its exact behaviour before you use it.
Runs enterprise networks and security for a living, and writes Shore Up to turn two decades of hands-on Linux, Windows and mail-server work into guides you can actually use.
More about the author →Was this article helpful?
Tap a star — no sign-in needed.
Be the first to rate this article.
