Dovecot 2.3 to 2.4 update problems

Dovecot, which is a secure IMAP server, released version 2.4.0 on 24 January 2025 and a minor revision of 2.4.1 on 28 March 2025. As such, I recently decided to update my instances from the 2.3 branch (version 2.3.21.1 to be exact) to this new 2.4 branch. Though major revision updates can often be problematic, this one posed some additional challenges due to many backwards-incompatible changes. Though that linked upgrade documentation was helpful, I still ran into some problems with the update that I will explain in this post. Hopefully these tips will help others avoid some of the mistakes that I made.

My Dovecot IMAP configuration is rather simple, making some of the backwards-incompatible changes that applied to me easy enough to address:

  • Variable expansions (or so I thought; more on this one later)
  • Naming of userdb and passdb
    • These two directives now require a name, which can be the name of the lookup database or simply arbitrary
  • Arguments supplied to userdb and passdb separated into individual directives
    • Instead of having, say, passdb { args = username_format=%n $path_to_file }, the args are separated into:
      • passdb_driver = passwd-file
      • auth_username_format =
      • passwd_file_path = $path_to_file
  • Changes to the names of some directives (including SSL)
    • ssl_cert became ssl_server_cert_file
    • ssl_key became ssl_server_key_file
  • Separation of the mail_location directive into individual components
    • Instead of having mail_location = $mailbox_format:$mailbox_path (e.g. mail_location = maildir:/var/mail/), it is now:
      • mail_driver = $mailbox_format –> mail_driver = maildir
      • mail_path = $mailbox_path –> mail_path = /var/mail/
      • mail_home = $mailbox_home –> mail_home = /var/mail/home
  • Some new defaults for base settings
    • The base_dir now defaults to /var/run/dovecot, so it should be omitted and shouldn’t be changed
    • The listen directive now defaults to listen = *, ::, which will listen on all available IPv4 and IPv6 addresses
    • The disable_plaintext_auth directive was renamed to auth_allow_cleartext and now defaults to no for better security

I also took this upgrade window as an opportunity to shift all of my configuration from the included conf.d/ files to a single dovecot.conf file with all of my settings. Though I was able to make a copy of my Dovecot 2.3 configuration files that I could modify in preparation for the update to Dovecot 2.4, the new configuration didn’t work perfectly.

SSL errors when starting Dovecot

The first unexpected error I encountered was when trying to start Dovecot 2.4 with my new configuration. It refused to start, throwing an error message of ‘SSL certificates too long’. The problem here ended up being that certificates no longer need to be redirected into the directive. More simply put, the less-than sign (<) needed to be removed from the certificate lines:

In Dovecot 2.3:
ssl_cert = </etc/ssl/mail_server/fullchain.pem
ssl_key = </etc/ssl/mail_server/privkey.pem
In Dovecot 2.4
ssl_server_cert_file = /etc/ssl/mail_server/fullchain.pem
ssl_server_key_file = /etc/ssl/mail_server/privkey.pem
The important part here is that the ‘<‘ has been removed for each of the SSL server files (both cert and key).

Variable expansion not working as intended

With the documentation provided by the Dovecot team regarding changes to variables, I thought that the expansion would be a non-issue, but I was mistaken. After upgrading to Dovecot 2.4, I could no longer log in to any of my email addresses across multiple domains using any of my IMAP clients. Looking at the mail authentication logs, I found many error messages similar to this one:

Jul 03 00:57:06 [dovecot] auth(z@z-issue.com,$IP,sasl:login): passwd-file: missing passwd file: /var/mail/vhosts/%domain/shadow

This first error was a simple syntax mistake on my part where I accidentally omitted the needed curly braces around any variables. In particular, I referenced %domain instead of %{domain} in many directives, such as mail_home, mail_path, and for this exact error, the passwd_file_path line of passdb.

After correcting my mistake by adding the curly braces, I anticipated the problem would be resolved. However, I was still unable to log in using my IMAP clients. The error messages in the mail authentication logs did change, though, to ones like this:

Jul 03 01:14:52 [dovecot] auth(z@z-issue.com,$IP,sasl:cram-md5)<+ssPdf84tMAYz+f6>: Error: passwd-file: Failed to expand passwd-file path /var/mail/vhosts/%{domain}/shadow: domain: No value to get domain from

This error was more obtuse to me. The %{domain} variable should have been available based on the email address logging in. In this error message above, the email address (which is a fake example) of z@z-issue.com should have resulted in:

%{user} --> expanding to 'z'
%{domain} --> expanding to 'z-issue.com'

but it didn’t. Looking again at the Dovecot 2.4 upgrade documentation for variable expansion, I finally figured out what I needed to do. In the table under the ‘List of common short variables and their replacements‘, the row showing %d being replaced by %{user|domain} was confusing to me. I wrongly interpreted that syntax as the boolean “or” in Regular Expressions (RegEx), meaning that I can use %{user} as a variable containing the username portion of the email address, and %{domain} as a variable containing the domain portion of the email address.

My interpretation of that syntax was incorrect. The chart is showing the literal variable to use, and the pipe (or vertical bar) here is serving as a filter. That results in the variable expansion being:

Old variableNew syntaxExplanation
%d%{user|domain}Referencing the ‘user’ variable, extract only the ‘domain’ portion.
%n%{user|username}Referencing the ‘user’ variable, extract only the ‘username’ portion.

Now that I understood the proper syntax, I was able to update the relevant sections of my Dovecot auth directives:

mail_driver = maildir
mail_home = /var/mail/vhosts/%{user|domain}/%{user|username}/
mail_path = /var/mail/vhosts/%{user|domain}/%{user|username}/

userdb passwd-file {
        userdb_driver = passwd-file
        auth_username_format = %{user|username}
        passwd_file_path = /var/mail/vhosts/%{user|domain}/passwd
}

passdb passwd-file {
        passdb_driver = passwd-file
        auth_username_format = %{user|username}
        passwd_file_path = /var/mail/vhosts/%{user|domain}/shadow
}

After restarting Dovecot, I was able to connect via my IMAP clients once again.

Cheers,
Nathan Zachary

12 comments

Skip to comment form

  1. Haha, joining the %{domain} club here, thanks a bunch for your post, that syntax was unexpected!

      • Zach on Tuesday, 21 October 2025 at 09:54
        Author
      • Reply

      You’re welcome, Tom. I’m glad that the article helped you, but also sorry that you fell victim to the obtuse Dovecot documentation.

      Cheers,
      Nathan Zachary

    • Gregoire G on Monday, 20 October 2025 at 17:59
    • Reply

    Spent hours on this f… %{user|domain}. I was also writing ${domain}. So confusing. Completely stupid syntax. Thank you so much for the post.

      • Zach on Monday, 20 October 2025 at 18:22
        Author
      • Reply

      You’re welcome, Gregoire. I’m glad that the post helped you.

      Cheers,
      Nathan Zachary

      • bohwaz on Tuesday, 21 October 2025 at 18:54
      • Reply

      Same for me. This was the worst config upgrade I ever had to do.

      Everything has changed, but slightly.

      I’m sure I’ll never install another Dovecot instance anywhere now.

      Thanks for the blog post!

        • Zach on Tuesday, 21 October 2025 at 20:46
          Author
        • Reply

        Hello Bowhaz,

        I’m glad that the article helped you. It’s really unfortunate that the Dovecot team didn’t put more effort into the documentation to support the update. However, I still find it to be the best IMAP server for my needs. I’ll just have to be more careful when staging my upgrades in the future.

        Cheers,
        Nathan Zachary

    • Vlad Mocanu on Tuesday, 9 September 2025 at 02:31
    • Reply

    God, bless you! Thank you for sharing this.

      • Zach on Tuesday, 9 September 2025 at 10:19
        Author
      • Reply

      You’re welcome, Vlad. I’m glad that the article helped you.

    • zim on Sunday, 24 August 2025 at 15:29
    • Reply

    Also helpful for me – I found the official upgrade notes to be poorly written. Thanks!

      • Zach on Monday, 25 August 2025 at 11:34
        Author
      • Reply

      You’re welcome. I’m glad that my post helped with your upgrade.

      Cheers,
      Nathan Zachary

    • Adam Reece on Sunday, 17 August 2025 at 13:48
    • Reply

    Thank you very much for this. Important steps here for Debian 12 to 13 upgrade!

      • Zach on Monday, 18 August 2025 at 13:19
        Author
      • Reply

      You’re welcome, Adam. I’m glad that it helped you with your Debian upgrade. 🙂

      Cheers,
      Nathan Zachary

Leave a Reply to bohwaz Cancel reply

Your email address will not be published.