Anyone managing Dovecot mail servers knows that while its indexing engine is fast and dependable, metadata mismatches with the underlying filesystem can disrupt specific mailboxes without warning.
I recently ran into an intriguing failure: a single email account on the server stopped syncing and failed expunge operations, while all other mailboxes under the same domain operated smoothly. Checking the logs revealed that doveadm exited with return code 75 (EX_TEMPFAIL), reporting that a path was Not a directory.
Here is how I traced the Maildir++ structure, why Dovecot confused a Sieve filter script with an IMAP message folder, and how to restore clean indexing without data loss.
1. Initial symptom and doveadm error code 75#
The problem surfaced when scheduled maintenance tasks and manual cleanup (expunge) commands began failing for user@domain.com:
Error: “/usr/bin/doveadm” reported error code “75” when it terminated:
doveadm(user@domain.com): Error: maildir: stat(/home/user/mail/domain.com/user/.dovecot.sieve/tmp) failed: Not a directory
doveadm(user@domain.com): Error: cmd expunge: Syncing mailbox INBOX.dovecot.sieve failed: stat(/home/user/mail/domain.com/user/.dovecot.sieve/tmp) failed: Not a directory
The core failure is: stat(.../.dovecot.sieve/tmp) failed: Not a directory.
Under the Maildir++ specification, any mailbox directory must contain three subdirectories: cur, new, and tmp. Dovecot was attempting to synchronize an imaginary IMAP folder called INBOX.dovecot.sieve, expecting a tmp/ subdirectory inside it. Because .dovecot.sieve is a flat file symlink rather than a directory, the operating system returned an immediate error.
2. Investigating the maildir structure and Sieve symlink#
To determine why Dovecot treated a configuration file as an IMAP folder, I checked the filesystem inside the account's mail directory:
[root@server ~]# ls -la /home/user/mail/domain.com/user/.dovecot.sieve
lrwxrwxrwx 1 user user 21 Jan 21 13:33 /home/user/mail/domain.com/user/.dovecot.sieve -> sieve/roundcube.sieve
The .dovecot.sieve entry at the root of the Maildir was a symbolic link pointing to the Roundcube webmail filter script (sieve/roundcube.sieve).
Comparing it against an unaffected account under the same domain (support@domain.com):
[root@server ~]# ls -la /home/user/mail/domain.com/support/ | grep .dovecot
-rw-r----- 1 user user 0 Jan 24 dovecot-acl-list
-rw-r----- 1 user user 6856 Feb 1 dovecot.index
-rw-r----- 1 user user 812524 Jul 3 dovecot.index.cache
-rw-r----- 1 user user 5000 Jul 3 dovecot.index.log
-rw-r----- 1 user user 7632 Feb 1 dovecot.list.index
-rw-r----- 1 user user 4044 May 4 dovecot.list.index.log
-rw-r----- 1 user user 54 Apr 2 dovecot-quota
-rw-r----- 1 user user 40589 Apr 2 dovecot-uidlist
The support mailbox lacked the .dovecot.sieve symlink entirely because no filters had been configured through webmail.
Returning to the affected account, I inspected the internal Dovecot index files:
[root@server ~]# ls -la /home/user/mail/domain.com/user/ | grep .dov
-rw-r----- 1 user user 3944 Jun 15 dovecot.index
-rw-r----- 1 user user 226172 Jun 15 dovecot.index.cache
-rw-r----- 1 user user 16992 Jun 15 dovecot.index.log
-rw-r----- 1 user user 7720 Jun 15 dovecot.list.index
-rw-r----- 1 user user 4108 Jun 15 dovecot.list.index.log
-rw------- 1 user user 236 Jan 21 .dovecot.svbin
-rw-r----- 1 user user 10454 Jun 15 dovecot-uidlist
The compiled Sieve binary .dovecot.svbin was present, confirming that Sieve was functional. The issue was an inconsistent state in the folder list index (dovecot.list.index): after an interrupted folder rename or restore, Dovecot registered .dovecot.sieve as a Maildir++ subfolder (where folders begin with a dot, such as .Sent or .Trash).
3. Resolving ambiguity and forcing index resynchronization#
To repair the mailbox, I temporarily removed the ambiguous symlink and instructed Dovecot to re-examine the filesystem:
# Step 1: Remove the conflicting symlink at Maildir root
rm /home/user/mail/domain.com/user/.dovecot.sieve
# Step 2: Force a full resync of the INBOX index
doveadm force-resync -u user@domain.com INBOX
The doveadm force-resync command audits the directory tree, eliminates orphaned records from dovecot.index, and rebuilds the mailbox layout without the phantom INBOX.dovecot.sieve entry. The command completed cleanly with exit code 0.
4. Real-time IMAP traffic validation#
To confirm normal mailbox operations without hanging login processes, I monitored the mail log:
tail -f /var/log/maillog | grep -i "user@domain.com"
The log confirmed clean IMAP sessions from webmail and desktop clients:
dovecot: imap-login: Logged in: user=<user@domain.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, secured
dovecot: imap(user@domain.com): Disconnected: Logged out in=82, out=950, bytes=82/950
dovecot: imap-login: Logged in: user=<user@domain.com>, method=PLAIN, rip=127.0.0.1, lip=127.0.0.1, secured
dovecot: imap(user@domain.com): Disconnected: Logged out in=427, out=38510, bytes=427/38510
Expunge and folder listing operations proceeded without returning error 75.
5. Auditing other mailboxes on the server#
To verify whether other accounts had similar symlinks and check their health, I ran a scan across the mail directory:
find /home/user/mail/ -name ".dovecot.sieve" -type l -exec ls -l {} +
Active symlinks were present in accounts such as contact@domain.com and billing@domain.com. I checked their Sieve status via CLI:
doveadm sieve list -u contact@domain.com
doveadm sieve list -u billing@domain.com
Both reported roundcube ACTIVE without errors, confirming that the symlink itself is not flawed; the failure was isolated to an index misalignment on the affected mailbox.
6. Preventive automation and maildir++ takeaways#
To catch stale or broken Sieve symlinks left behind by webmail clients, I added a simple audit check:
#!/bin/bash
# Sieve symlink integrity check for Maildir setups
for user in $(doveadm user '*' | cut -d'@' -f1); do
SIEVE_LINK="/home/user/mail/domain.com/$user/.dovecot.sieve"
if [ -L "$SIEVE_LINK" ]; then
if [ ! -e "$SIEVE_LINK" ]; then
echo "Notice: Broken symlink found for user: $user"
fi
fi
done
Maildir++ takeaway#
In the Maildir++ structure, any dot-prefixed file (.FolderName) sitting alongside the INBOX root can be cataloged as an IMAP subfolder if index corruption occurs. When a stat() call looks for a tmp/ subdirectory within a flat file, removing the conflicting file and invoking doveadm force-resync reliably clears the error state.
Was this article helpful?
Leave a quick reaction to help prioritize future technical guides:
This post is licensed under CC BY-NC.



Comments
Join the discussion below.
0 comments