In my last post, I explained how I went about setting up a new email server using Chasquid and Dovecot. This post will build on that, so be sure to read that one first, if you haven’t already.
Today we’ll look at what’s required to actually get mail delivered to the new server. We’ll first set up a new domain, and then add email accounts to it.
TLDR: This post outlines the process for setting things up. If you don’t care about the details, I have a set of shell scripts that I’ve written to automate most of this.
Adding an Email Domain
To add an email domain to the server, we need to set up a bunch of files and directories. Replace example.com with the actual email domain, obviously.
sudo mkdir /etc/chasquid/{domains,certs}/example.com
sudo touch /etc/chasquid/domains/example.com/{aliases,passwd,users}
sudo chown -R chasquid:chasquid /etc/chasquid/domains
sudo chown -R dovecot.dovecot
sudo chown dovecot:dovecot /etc/chasquid/domains.example.com/passwd
sudo chmod 0660 /etc/chasquid/domains/example.com/*
This creates directories under /etc/chasquid
for the configuration (domains
) and certificates (certs
) for the example.com domain.
We then add three files: aliases
, which will hold any email aliases that are set up on the domain; passwd
, which will contain the usernames and passwords for email accounts added to the domain; and users
, which will contain the account information for any Chasquid-only user accounts. Chasquid accounts are handy when you want to be able to send mail, such as from an application, but don’t need an accompanying mailbox to go with it. We’ll cover these in the next post.
Once everything is created, we set the ownership of the files to the user running chasquid (or, in the case of the passwd
file, the user running Dovecot) to ensure that those users can write to the files.
DKIM Signing
DKIM (DomainKeys Identified Mail) is an anti-spam measure where the sending server signs outgoing messages using a private key. The associated public key is published to the domain’s DNS records, where a receiving server can access it and verify that the message came from an authorized sender. Many large email providers, including GMail and Microsoft, are now requiring domains that send large volumes of mail to use DKIM or risk having their mail treated as spam. Even if your domain doesn’t reach the threshold to require it, it’s still a smart idea to use DKIM.
The latest versions of Chasquid (>=1.14) have built-in DKIM signing, but unfortunately the version currently installed by Debian Bookworm is a bit older (1.12 as of this writing), so we’ll need to install a third-party tool to do the work.
I’m currently using the driusan/dkim DKIM utilities. These are written in Go and require compiling, so you’ll need to install the Go compiler (note: Go 1.25.1 was current at the time of writing, be sure to check the Go downloads page for the most up-to-date version).
wget https://go.dev/dl/go1.25.1.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.25.1.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
Then run the following commands to build and install the dkimsign
, dkimverify
, and dkimkeygen
utilities:
go install github.com/driusan/dkim/cmd/dkimsign@latest
go install github.com/driusan/dkim/cmd/dkimverify@latest
go install github.com/driusan/dkim/cmd/dkimkeygen@latest
sudo cp ~/go/bin/{dkimsign,dkimverify,dkimkeygen} /usr/local/bin
Next, we need to create a DKIM signing key. This needs to be done for each domain.
First, switch to the domain’s directory under /etc/chasquid/certs
:
cd /etc/chasquid/certs/example.com
Then run the dkimkeygen
command:
sudo dkimkeygen
This will create two files in the directory, private.pem
which contains the private key, and dns.txt
which contains the public key in the format needed for the DNS record. Chasquid needs the key file to be named dkim_privkey.pem
.
sudo mv private.pem dkim_privkey.pem
Next, you’ll need to create a dkim_selector
file in the domain’s directory under domains. The selector can be whatever you want (“mail” is common). I like to use the machine’s hostname and today’s date. This gives me the ability to easily rotate keys or change email servers while also keeping the old public keys available so that receiving servers can still verify older mail.
sudo echo $(hostname -s)$(date +'%Y%m%d') | sudo tee /etc/chasquid/domains/example.com/dkim_selector
Finally, you’ll need to create a new record on your domain’s DNS server with the contents of the dns.txt
file. The record should be a TXT
record, the record name should be exampleYYYYMMDD._domainkey.example.com
(substituting the selector name you created above and the proper domain name, of course) and the content should be the entire contents of the file.
Each time Chasquid receives an email message, it runs the post-data
script (found in /etc/chasquid/hooks
) to see what further processing it should be before delivering it to either Dovecot or to the intended recipient’s SMTP server. The post data script that is included in the Debian distro is set up to automatically handle DKIM signing or validation (depending on whether it’s an outgoing or incoming message) if it can find the DKIM utilities we just compiled and a valid signing certificate (for outgoing mail), so no additional configuration is necessary.
TLS Certificates
Chasquid requires that TLS be enabled for clients submitting mail to be delivered, so we’ll first need to get a certificate. (Mail coming in from other servers does not strictly require TLS, but Chasquid has a nice feature that blocks mail coming in on a non-secured connection when it has previously seen mail from the same domain that is secured. This isn’t a huge deal in my setup, since all of my mail first passes through my spam filtering service, MXGuarddog, so only their servers interact with mine, but it can help prevent some spam from getting in when outside servers are interfacing with Chasquid directly.)
While not strictly required, I’m using a separate certificate for each domain that I’m hosting. This lets my users access their mailboxes using “mail.specificdomain.com” in their mail clients without needing to accept any invalid certificates and it makes for a seamless transition if I ever decide to split any domains off to different servers in the future.
I’m getting my certificates from Let’s Encrypt and I’m using the Lego ACME client to do it. Chasquid is actually set up to interface nicely with Certbot, but because I’m using the Caddy webserver on this machine, and Caddy has it’s own ACME client, it would have been difficult (if not impossible) to get Certbot working correctly. Lego can interface directly with my DNS servers (running PowerDNS), which is what prompted me to go that route.
Assuming you’re also using PDNS, before attempting to obtain a cert, you’ll need to ensure that the PowerDNS API is running on your DNS server (it is not on by default) and you’ll need your server’s API key. Use caution in doing this, as an improperly set up API could let an attacker into your system. You can find instructions for enabling the API on the PowerDNS site.
Now that we’re ready to go, we’ll first install Lego and create a directory where the certificates will be stored.
sudo apt update
sudo apt install lego
sudo mkdir -p /etc/chasquid/.lego/certificates
sudo chmod 755 /etc/chasquid/.lego /etc/chasquid/.lego/certificates
Lego looks for PDNS_API_URL
and PDNS_API_KEY
environment variables to interface with the DNS server, so set these as appropriate.
PDNS_API_URL=https://dns.example.com/
PDNS_API_KEY=ENTER_API_KEY
With those set, we can request the certificate. I use the singular ‘mail.example.com’ hostname to access all services, but if you’d prefer additional names, such as ‘smtp’, ‘pop3’, or ‘imap’, you can add them with additional -d
parameters and they’ll also be added to the certificate.
sudo lego --dns pdns --accept-tos --email your.address@example.com --path /etc/chasquid/.lego -d mail.example.com run
Since Chasquid is expecting Certbot’s naming conventions, but Lego uses a different one, we’ll symlink the certificates to where Chasquid expects them to be:
sudo ln -s /etc/chasquid/.lego/certificates/mail.example.com.crt /home/chasquid/certs/mail.example.com/fullchain.pem
sudo ln -s /etc/chasquid/.lego/certificates/mail.example.com.key /home/chasquid/certs/mail.example.com/privkey.pem
To add the certs to Dovecot, we’ll create a config file in /etc/dovecot/domains
that points to the certificate files.
cat << EOF | sudo tee /etc/dovecot/domains/mail.example.conf
local_name mail.$1 {
ssl_cert = </etc/chasquid/certs/example/fullchain.pem
ssl_key = </etc/chasquid/certs/example/privkey.pem
}
EOF
Finally, we’ll restart/reload the servers so that they’ll pick up the new configuration (reloading is generally preferred over a full restart, but Chasquid only has a restart option).
systemctl reload dovecot
systemctl restart chasquid
Creating Email Accounts
Now that the domain is set up, the only thing left to do is add users. To do this, you’ll need two things: the desired email address and a password.
Passwords are stored as hashes in the /etc/chasquid/domains/example.com/passwd
file. The doveadm pw
command can be used to hash the password with the Dovecot server’s preferred hashing method:
PASSWD=$(doveadm pw)
This will prompt for a password and return the hash, which will be stored in a shell variable named PASSWD
.
To create the user account, append a line to the passwd
file like so:
echo "user@example.com:$PASSWD:dovenull:dovenull:::::" >>/etc/chasquid/domains/example.com/passwd
The first field contains the username, which is the full email address; next is the password hash, as returned above; and ‘dovenull’ is the user and group that will “own” the user’s mailbox on the server. The remaining fields are not needed for this specific setup, so we leave them empty, hence the ‘:::::’ at the end of the file. Some additional features that could be added include the directory where mail should be placed (which would override the global value we set up in Part 1), mailbox quotas (which I’m not using), and network restrictions (to only allow access to the mailbox from certain subnets, for example), among other things.
Once the user is written to the file, they’ll be able to log in using their favorite email client and receive mail sent by other users.
MXGuarddog
In part one, I mentioned that I’m using a third-party spam filtering service, MXGuarddog, to filter my mail. All mail for my domains first gets delivered to them, they scan it, and then forward the legitimate mail on to my Chasquid server. In order to do this, they need to know the email addresses to accept.
At this point, if you’re using MXGuarddog or a similar service, don’t forget to set up the new account with the service provider.
MX Record
The final set in setting up a mail server is setting an MX, or mail exchanger, record in your domain’s DNS. The MX record tells mail senders where to find the server that handles mail for your domain.
The MX record should have the fully qualified domain name that will be used for addressing mail as it’s name (example.com), and the name of the server that will receive it’s mail as the record’s contents (mail.example.com). It should also have a priority which is used to determine the order in which servers are tried if there is more than one MX record. If you only have one server, set the priority to 10.
If you’re using a third-party service like MXGuarddog to process your mail, be sure to use the MX record settings they provide to ensure you mail gets routed correctly.
Wrapping Up
We now have a fully functional mail server that can send, receive, and deliver messages for our users. In the next post, I’ll cover the remaining loose ends of the setup, such as aliases and pipes, TLS certificate renewal, send-only email accounts (and why you might want them), and how to set up auxiliary services, like SpamAssassin or ClamAV.
Note: I may receive service credits from MXGuarddog for mentioning them here. Regardless, they’ve been a great provider who I’ve been paying a modest sum to manage my spam for years, and my recommendation is genuine.