Server Name Indication (SNI) for qmail and dovecot

February 25, 2026 by Roberto Puzzanghera 0 comments

Server Name Indication (SNI) is a TLS extension that enables a server to present different certificates based on the hostname requested by the client during the TLS handshake.

In modern email environments, multiple domains frequently share the same IP address for SMTP, IMAP, POP3 and submission services. Without SNI, a mail server can expose only a single certificate per listening socket, forcing administrators to rely on multi-domain (SAN) certificates or wildcard certificates. This approach increases operational problems among unexperienced end users, who are unable to use the client wizards to correctly configure their mailboxes.

Enabling SNI in mail services allows the server to present the appropriate certificate based on the hostname requested by the client, contained in its email address.

The SNI support for my qmail distribution has been added by Andreas Gerstlauer (commits here and here), whom I would like to thank.

Building the certificates

Suppose we want to create different certificates for domain1.tld and for domain2.tld. Let's use dehydrated to create the two certs. Modify /etc/dehydrated/domains.txt in this way:

domain1.tld imap.domain1.tld pop3.domain1.tld smtp.domain1.tld
domain2.tld imap.domain2.tld pop3.domain2.tld smtp.domain2.tld

As you know, as soon as you run dehydrated -c, a specific certificate is built for each row in domains.txt. The name of each certificate is the first domain name of the row. The other domains in the same row are alternative names (SAN) for the same certificate. You have to put there all domains that clients' wizards will try to guess while configuring the mailbox. For example, if you are configuring roberto@sagredo.eu, the wizard will probably look for smtp.sagredo.eu for the SMTP server and imap.sagredo.eu for the IMAP.

In qmail, domain-specific SSL certificates for servers that are reachable under different names when the client supports SNI have to be set into

QMAILDIR/control/servercerts/<FQDN>/servercert.pem

I modified the dehydrated's hook.sh script in order to put the first certificate (first row in domains.txt) in

QMAILDIR/control/servercert.pem

and all the other certificates, starting from line two, in

QMAILDIR/control/servercerts/<FQDN>/servercert.pem

QMAILDIR/control/servercert.pem is used as default, when an appropriate certificate for the required hostname cannot be found on the server.

In our example we'll have the following certificates:

QMAILDIR/control/servercert/servercert.pem
QMAILDIR/control/servercerts/domain2.tld/servercert.pem

Concerning dovecot, you need to declare the additional certificates for SNI in the following way:

local_name domain2.tld { 
 ssl_server_cert_file = /etc/dehydrated/certs/domain2.tld/fullchain.pem 
 ssl_server_key_file  = /etc/dehydrated/certs/domain2.tld/privkey.pem 
} 
local_name *.domain2.tld { 
 ssl_server_cert_file = /etc/dehydrated/certs/test.sagredo.eu/fullchain.pem 
 ssl_server_key_file  = /etc/dehydrated/certs/test.sagredo.eu/privkey.pem 
}

The above settings for dovecot will be added for you by the hook script.

Testing the certificate

To test SNI with openssl you have to pass the -servername option.

openssl s_client -starttls smtp -connect serverIP:587 -servername domain2.tld 2>/dev/null | grep subject=CN

Basically, you are connecting to the mail server's IP and asking for a certificate for the domain domain2.tld. If the server doesn't ship any certificate for domain2.tld, then the default one will be served, which is /var/qmail/control/servercert.pem.

At the end of the certificate you have the Common Name (CN):

subject=CN = domain2.tld

which is the FQDN for which the certificate has been released. If you get domain2.tld or smtp.domain2.tld or any domain having domain2.tld as a secondary level domain, then your SNI is working and your client is able to indicate the certificate related to the domain it is connecting from.

Same example for IMAP and POP3 protocols:

# openssl s_client -connect serverIP:995 -servername domain2.tld 2>/dev/null | grep subject=CN
subject=CN = domain2.tld

# openssl s_client -connect serverIP:993 -servername domain2.tld 2>/dev/null | grep subject=CN
subject=CN = domain2.tld

The SAN (Subject Alternative Name) of the certificate is the list of the domains which are protected by the same certificate:

# openssl x509 -in /var/qmail/control/servercert.pem -noout -text | grep -A1 "Subject Alternative Name"     
           X509v3 Subject Alternative Name:  
               DNS:domain1.tld, DNS:smtp.domain1.tld, DNS:imap.domain1.tld, DNS:pop3.domain1.tld,

You can get the SAN when connecting from remote in the following way:

openssl s_client -starttls smtp -connect domain1.tld:587 2>/dev/null |
  openssl x509 -noout -text | 
  grep -A1 "Subject Alternative Name"

Add a comment

Recent comments
See also...
Recent posts

RSS feeds