Run Several doveadm Commands Across Selected Mail Users

Running the same doveadm command against a hundred mailboxes one at a time is slow, and doveadm batch exists to fix exactly that. This guide covers running a sequence of mailbox commands for one user, a wildcard group, or a file of usernames. The installed package is Dovecot 2.3.21+dfsg1-2ubuntu6.5 from dovecot-core. Allow about 15 minutes: most of the work is checking the user scope and command separators before anything runs.

The examples use read-only commands. You need an account allowed to use doveadm against the Dovecot install. A command that changes, moves or deletes mail may need elevated privileges or a Dovecot admin socket, depending on the host.

1. Understand what batch changes

doveadm batch runs multiple doveadm commands in sequence for each selected user. Its point is letting Dovecot group mailbox work per user, instead of walking the whole user set again for every separate invocation.

It doesn't invent a user list. Pick one of three scopes:

Without any of those, the sequence runs under the currently logged-in user's environment, not as an implicit all-users operation. That default is easy to miss.

2. Run a sequence for one user

Start with a single known account and two read-only commands. The colon separates commands:

$ doveadm batch -u '[email protected]' : mailbox list : quota get

Each selected user's mailbox list runs first, then quota get. If the account doesn't exist, the command fails rather than silently turning the typo into an all-users request.

Checkpoint: repeat with a real test account and confirm it returns that account's mailbox and quota data. On this machine, a deliberately absent account produced User doesn't exist and exit status 67, useful evidence that the selection was applied.

3. Widen the scope with a quoted mask

Use a mask when the same sequence needs to cover a domain or another predictable group:

$ doveadm batch -u '*@example.net' : mailbox list : quota get

Quote the mask. Without quotes, the shell can expand * against filenames in the current directory before doveadm ever sees it. ? is also supported. Test a narrow mask first, then widen it only once the output and account count look right.

An empty result isn't proof the command was safe for every account. Check the user database and the exact mask separately if the result is unexpectedly empty: a wildcard is still a potentially large operation.

4. Use a file when the user list is explicit

Build a reviewable input file, one username per line:

$ umask 077
$ printf '%s\n' '[email protected]' '[email protected]' > /tmp/doveadm-users.txt
$ doveadm batch -F /tmp/doveadm-users.txt : mailbox list : quota get

-F reads the file as usernames, not a shell command or a comma-separated list. Review it before running the batch:

$ sed -n '1,20p' /tmp/doveadm-users.txt
[email protected]
[email protected]

Keep this file private since email addresses count as operational data. Remove it once you're done:

$ rm -- /tmp/doveadm-users.txt

That removal only deletes the temporary username list. It doesn't undo any mailbox command: if a batch command changed mail, recovery depends on that command's own backup or reversal procedure.

5. Pick a separator the shell will actually preserve

The separator is exactly one character. A colon usually works well since it has no special meaning in an unquoted shell word:

$ doveadm batch -u '[email protected]' : mailbox list : quota get

Don't use an unquoted semicolon or ampersand as the separator. The shell can treat those as control operators, so doveadm receives only part of the intended command while the shell runs the rest itself. Choosing another separator? Quote it and check the complete command in your shell history before running it.

Commands inside the batch take their normal arguments but must not use the batch-level -A, -S or -u options. Set the user scope once on batch, not again inside each command.

6. Treat all-user and mutating batches as a real change

Warning: -A can reach every account the configured user database returns. With userdb { driver = passwd }, the manual warns that system users below first_valid_uid can show up too. SQL and LDAP setups need working iteration settings, SQL's iterate_query or LDAP's iterate_attrs and iterate_filter, or Dovecot may miss users you expected it to find.

Do the read-only discovery first. Only after checking the scope should you consider a state-changing sequence such as the manual's own alternative-storage example:

$ doveadm batch -u '*@example.net' : altmove seen savedbefore 30d : purge

That's not a harmless test: it moves matching mail, then purges zero-reference-count messages from primary storage. Don't paste it into production without a backup, a tested recovery path and a deliberately small first scope. doveadm batch has no generic undo.

7. Check connectivity and remote execution separately

The optional -S argument points to an absolute local Unix socket or a hostname:port TCP endpoint, letting an administrator send mail commands through it:

$ doveadm batch -S /run/dovecot/admin : mailbox list

Use the socket path your own install configures: /run/dovecot/admin above is just an example, not a default this guide asserts. A socket or TCP endpoint is security-sensitive, so confirm ownership, permissions, transport and authentication policy before using it across hosts. Keep credentials and connection details out of shared shell history.

Add -v for a progress counter or -D when debugging configuration and connection problems. The global -o setting=value option can override a Dovecot setting for one invocation; record any override in your change notes, since it isn't a permanent configuration edit.

Done means