Expunge old mails by folder and age in Dovecot

Keeping mailboxes lean is essential for performance and storage management on self-hosted email servers. Over time, folders like Trash, Junk, or even custom folders such as Newsletters or Archive can accumulate old messages that serve no ongoing purpose.

This guide demonstrates how to automatically remove (expunge) old messages from selected folders based on their age using Dovecot’s native doveadm utility. The method is simple, scriptable, and integrates cleanly into any system via cron.

Preview: What would be deleted? (Dry Run)

Before deleting anything, you can preview which messages would be expunged by using doveadm fetch.

Example:

doveadm fetch -A 'uid flags subject' mailbox Trash savedbefore 30d

This lists all messages in the Trash folder that are older than 30 days, including:

  • UID (unique message ID per folder)
  • Flags (e.g. \Seen, \Deleted)
  • Subject line (for identification)

You can replace the folder and retention period as needed:

doveadm fetch -A 'uid subject' mailbox Newsletters savedbefore 45d

This helps verify your rules before running actual expunge commands.

Script Location and Structure

We place the script in a controlled location under:

/root/dovecot-autoclean/dovecot_expunge.sh
#!/bin/bash

# Path to doveadm binary
DOVEADM="/usr/bin/doveadm"

# Expunge mails older than the defined age from specified folders
$DOVEADM expunge -A mailbox Trash       savedbefore 30d
$DOVEADM expunge -A mailbox Junk        savedbefore 90d
$DOVEADM expunge -A mailbox Newsletters savedbefore 45d

Make the script executable:

chmod +x /root/dovecot-autoclean/dovecot_expunge.sh

You can customize both folder names and the age (savedbefore) to match your needs. The folder names must exactly match their IMAP representation.

Cron Integration (no systemd)

We recommend scheduling the script once daily. Two common options:

Option 1: crontab -e (user-specific, e.g. root)

Run:

crontab -e

Add the following line to run the script at 03:30 every night:

30 3 * * * /root/dovecot-autoclean/dovecot_expunge.sh

Option 2: /etc/crontab (system-wide)

Alternatively, edit /etc/crontab and insert:

30 3   * * *   root   /root/dovecot-autoclean/dovecot_expunge.sh

This explicitly declares the user (root) and is preferred in environments with centralized cron management.

Manual Testing

Before relying on automation, test the script manually:

/root/dovecot-autoclean/dovecot_expunge.sh

This will run all expunge commands and print errors to the console if applicable.

Notes and Considerations

  • The -A flag requires doveadm to access a user list (e.g., via SQL, passwd, or LDAP).
  • If -A doesn’t work, you can loop over users manually (not covered here).
  • savedbefore 30d refers to the internal save timestamp, not the email’s Date: header.
  • Folder names are case-sensitive depending on your Dovecot namespace settings.
  • You can add more folders or adjust timeframes as needed, e.g.:
$DOVEADM expunge -A mailbox Projects-2021 savedbefore 180d

Summary

This method provides a lightweight, cron-based strategy for automatic email cleanup using Dovecot’s built-in tooling. It gives administrators fine-grained control over which folders are cleaned, and after how long—without installing additional software or relying on user behavior.

This article replaces the now deprecated script formerly hosted at github.com/filipnet/dovecot-autoclean, which will be removed shortly. All relevant instructions are now maintained here.