+++ title = "Setting up an email server in 2020 with Dovecot and OpenSMTPD: extras" +++ # This sequel to my earlier [guide](/blog/2020/email-server/) discusses extra tips and tricks to extend your email setup. This page will be updated continuously as I come up with ideas. Last updated 2020-04-27. ## General ### Multiple domains You can generalize your setup to handle multiple domains with very little effort. In the following, I'll assume that your two domains are called `foo.com` and `bar.com`. #### DNS records There should be MX, SPF, DKIM and DMARC records for both domains, as explained in the previous guide. Fortunately, all these records can have completely identical contents for both domains! However, it remains essential that the mail server's mailname and reverse DNS domain name match up exactly, so you should create MX records with that in mind. Therefore, if the email server for both domains has `mx1.foo.com` as reverse DNS name, the MX records should look like this: ```sh foo.com. MX 42 mx1.foo.com. bar.com. MX 42 mx1.foo.com. ``` This is perfectly valid: the only thing that matters is that what your SMTP server calls itself agrees with what reverse DNS says that the server is actually called. #### Dovecot To make Dovecot aware of multiple domains, you only need to update the `/etc/dovecot/users` file to add accounts for both domains. However, in the original guide, I said to only write `user` in the file, without the `@foo.com`, for an address `user@foo.com`. Unsurprisingly, that isn't an option when handling multiple domains, so you must put the full address in `/etc/dovecot/users`. Then update `/etc/dovecot/dovecot.conf` to reflect that change, by replacing `%n` with `%u` in `username_format`: ```sh userdb { driver = passwd-file args = username_format=%u /etc/dovecot/users override_fields = uid=vmail gid=vmail home=/home/vmail/%d/%n } ``` Also note the change in the `home` setting: the inbox of a user `user@foo.com` will now be stored in `/home/vmail/foo.com/user`. That's all you need to change. #### OpenSMTPD For OpenSMTPD, create a new file `/etc/smtpd/domains`, and in there put all desired domains on their own line: ```sh foo.com bar.com ``` And as I mentioned when discussing the DNS records, you should check that `/etc/smtpd/mailname` agrees with your server's reverse DNS. Then, in the main configuration file, tell OpenSMTPD to use the new domains file when deciding whether to accept an message, by declaring a new table and changing the `match` line for inbound mail: ```sh table domains "/etc/smtpd/domains" # ... match from any for domain action "RECV" ``` In theory, that's it! You should now have a working multi-domain email server. ## Dovecot ### Catchall inbox In Dovecot, you can create a catch-all inbox that will accept all emails sent to your domain that don't match anyone in `/etc/dovecot/users`. Just add another `userdb` block *after* the first: ```sh userdb { driver = static args = uid=vmail gid=vmail home=/var/vmail/catchall allow_all_users=yes } ``` The `static` driver means there is no table file: all configuration is directly within this `userdb` block. If we don't specify `allow_all_users=yes`, then Dovecot will check whether users exist using the `passdb` table, and will conclude that the recipient is invalid. ## OpenSMTPD ### Client certificates You can configure OpenSMTPD to request a client certificate for sending emails, in addition to or as a subsitute for passwords. In this guide I'll use it for subsitution. This is especially useful if you created a catch-all inbox, since this approach allows you to send messages from arbitrary names, as long as the client can present a valid certificate. It also allows you to get rid of the awkward duplication of user credentials between Dovecot and OpenSMTPD. #### Creating certificates We need to start with some cryptography to create and verify certificates. I recommend that you do all of this on your trusted *client* device, and only copy the necessary files to the server later. DISCLAIMER: All the keys and certificates that we'll generate in this section are for **private use** only, to handle a small number of trusted clients. I'm not a cryptography expert, so you should **not** listen to me for large-scale systems that may involve untrusted devices. The first step is to set up a private Certificate Authority (CA), which issues the client certificates and can be used to verify them. Start by generating an RSA private key, which you should store in a safe place and not share with anyone: ```sh $ openssl genrsa -out mailca.key 2048 ``` Extract a public certificate from this key as follows. Because we're lazy, we give it a lifetime of 36500 days: ```sh $ openssl req -new -x509 -days 36500 -key mailca.key -out mailca.crt ``` When running this command, OpenSSL will ask you some questions about who this certificate is intended for. Since this is for personal use, your answers don't matter, so just use the defaults. Some fields (I think only *Country Name* and *Organization Name*) cannot be empty, but the others can. Moving on to the client, once again generate an RSA private key: ```sh $ openssl genrsa -out mailclient.key 2048 ``` From this private key, create a Certificate Signing Request (CSR) as follows, where you'll be asked the same questions as before: ```sh $ openssl req -new -key mailclient.key -out mailclient.csr ``` By feeding this CSR to the CA, we can create a signed client certificate that can be verified using the CA's public certificate. ```sh $ openssl x509 -req -in mailclient.csr -out mailclient.crt \ -days 36499 -CA mailca.crt -CAkey mailca.key ``` If you want to create multiple distinct client certificates, just repeat the last few steps for each one. #### Server configuration OpenSMTPD needs to verify the validity of client certificates using the CA's public certificate, so you should copy that to somewhere on the server, e.g. `/etc/smtpd/mailca.crt`, and declare it to OpenSMTPD by adding this near the top of the file: ```sh ca "mailca" cert "/etc/smtpd/mailca.crt" ``` Then replace the entire configuration for outbound mail as follows. Note that this removes SMTPS support, leaving only STARTTLS, and that it also removes the need to enter a password: ```sh # Outbound listen on eth0 port 587 tls-require verify pki "example.com" ca "mailca" filter "rspamd" tag "VALID" action "SEND" relay srs match from any tag "VALID" for any action "SEND" ``` The magic word here is "`verify`", which tells OpenSMTPD to ask for a client certificate and to verify it using the given CA. The `tag "VALID"` at the end is to clarify that all emails that successfully pass through the first line are from trusted senders, because they presented a valid client certificate. #### Client configuration Now you won't be able to send emails if your client doesn't present its certificate to the server! Unfortunately, not all mail clients support this; personally I use [Thunderbird](https://www.thunderbird.net/) with success. I won't include any client-specific configuration here, but I will say this: For some clients (like Thunderbird), you'll have an easier time importing your client certificate if you encode it in the [PKCS #12](https://en.wikipedia.org/wiki/PKCS_12) storage format: ```sh $ openssl pkcs12 -export -in mailclient.crt -inkey mailclient.key \ -certfile mailca.crt -out mailclient.pfx ``` OpenSSL will ask you to set a password, which you'll need to enter again when importing the certificate into the client.