1. Overview

In today’s digital age, email remains a crucial communication tool. But with the ever-growing threat of spam and phishing attacks, simply setting up an email server isn’t enough. To ensure the legitimacy and security of our email communication, implementing robust security measures is essential. Fortunately, we can build a secure email server by combining the capabilities of three powerful tools named DKIM, Postfix, and Mailman.

In this tutorial, we’ll navigate through the process of setting up these tools on Ubuntu and discover how they work together to establish a highly secure and functional email server.

Before moving forward, let’s note that the only prerequisite for this operation is to have a domain and access to its DNS management console.

2. Setting up DKIM

DKIM (DomainKeys Identified Mail) is a utility that adds a layer of authentication to outgoing emails by digitally signing them with a private key generated on the server.

Let’s check out the process of setting up DKIM on Ubuntu.

2.1. Installing OpenDKIM

The first step is to install OpenDKIM, an open-source tool that provides DKIM signing for emails:

$ sudo apt install opendkim opendkim-tools

Once it’s installed, we perform some initial configuration by opening the OpenDKIM configuration file for editing:

$ sudo nano /etc/opendkim.conf

After opening it, let’s locate the Syslog line:

Syslog               yes

Then, let’s add another line to it to make OpenDKIM generate more informative logs, to help with debugging:

Logwhy               yes

Next, let’s find the Domain line:

#Domain                 example.com

The commented-out (#) line above indicates that the option is currently inactive and has a default value of example.com. Let’s make the option active by uncommenting the line and setting the value to our domain, i.e., domain.com:

Domain                 domain.com

Now, let’s perform some additional configuration in the next section.

2.2. Additional Configuration

In the /etc/opendkim.conf file, let’s locate these commented-out lines, which we’ll activate by uncommenting:

#Canonicalization   simple
#Mode               sv
#SubDomains         no

Above, Canonicalization indicates the canonicalization method to be utilized for signing emails. We’ll change its value to relaxed/simple for broader compatibility in terms of email header preparation.

Besides that, let’s keep the sv value for Mode to activate signing mode for outgoing emails and change the value of SubDomains to yes to turn on signing for subdomains:

Canonicalization   relaxed/simple
Mode               sv
SubDomains         yes

Furthermore, let’s add some more lines after the above ones:

AutoRestart yes
AutoRestartRate 10/1M
Background yes
DNSTimeout 5
SignatureAlgorithm rsa-sha256

We used five options above:

  • AutoRestart: enables automatic restart for OpenDKIM
  • AutoRestartRate: specifies the automatic restart rate
  • Background: runs OpenDKIM as a background process
  • DNSTimeout: specifies the maximum time for a DNS lookup
  • SignatureAlgorithm: The algorithm to be used for generating DKIM signatures

Finally, let’s add another group of lines at the end of the file:

KeyTable           refile:/etc/opendkim/KeyTable
SigningTable       refile:/etc/opendkim/SigningTable

ExternalIgnoreList  /etc/opendkim/TrustedHosts

InternalHosts       /etc/opendkim/TrustedHosts

Here, the KeyTable and SigningTable options indicate the location of KeyTable (containing DKIM keys) and SigningTable (domains for which emails are to be signed) files respectively. These files will be created later in the specified locations.

Moreover, ExternalIgnoreList specifies the external hosts to be ignored during signature verification and InternalHosts specifies the internal hosts whose emails are to be signed.

All these hosts are listed in the TrustedHosts file (to be created later in the specified location).

2.3. Creating Required Files

The next step is to create some files that are necessary for setting up DKIM.

Before creating them, let’s create two directories first:

$ sudo mkdir /etc/opendkim
$ sudo mkdir /etc/opendkim/keys

Then, let’s create the required files:

$ sudo touch /etc/opendkim/KeyTable
$ sudo touch /etc/opendkim/SigningTable
$ sudo touch /etc/opendkim/TrustedHosts

Now, let’s edit these files one-by-one. Primarily, let’s edit the /etc/opendkim/KeyTable file by adding a line to the end of it:

default._domainkey.domain.com     domain.com:default:/etc/opendkim/keys/domain.com/default.private

It connects the default DKIM selector, i.e., default._domainkey.domain.com to domain.com and specifies the private key file location, i.e., /etc/opendkim/keys/domain.com/default.private. When we generate DKIM keys in the next section, the private key will be stored in this location.

Secondly, let’s insert a couple of lines in the /etc/opendkim/SigningTable file:

*@domain.com default._domainkey.domain.com
*@*.domain.com default._domainkey.domain.com

Here, the first line indicates that email addresses ending with @domain.com are to be signed using the default DKIM selector and the second line suggests that subdomains are to be signed using that selector as well.

Again, let’s add some lines to the /etc/opendkim/TrustedHosts file:

127.0.0.1
localhost

*.domain.com

These lines add localhost and domain.com along with their subdomains to the list of trusted hosts. This tells OpenDKIM to only sign the emails sent from these hosts and not perform verification on them since they are trustworthy.

2.4. Generating DKIM Keys

Now, let’s create a private/public DKIM key pair, where the private key will be used for signing and the public key will be used for remote verification.

Firstly, let’s create a new directory using the domain name, i.e., domain.com:

$ mkdir /etc/opendkim/keys/domain.com

Then, we’ll generate a DKIM key pair:

$ sudo opendkim-genkey -b 2048 -d your-domain.com -D /etc/opendkim/keys/domain.com

We used three options in the above command:

  • -b, short for –bits, generates 2048-bit keys
  • -d, short for –domain, indicates the domain, i.e., domain.com
  • -D, short for –directory, specifies the directory where the keypair is to be stored

Next, let’s navigate to the /etc/opendkim/keys/domain.com/default.txt file and copy the public key from there. We’ll publish this in the DNS records in the next step.

After copying, let’s go to the particular section in our DNS management console that enables us to create DNS records:

Create TXT Record

Here, let’s choose TXT Record under Type as we want to create a new TXT record. Then, let’s insert default._domainkey under Host and paste the copied public key under Value. Besides that, let’s keep the TTL value set to Automatic.

Let’s save the TXT record to complete publishing the public key in the DNS records.

Finally, we restart OpenDKIM to apply the changes and finish setting up DKIM on the machine:

$ sudo systemctl restart opendkim

Let’s now move on to the next section.

3. Setting up Mailman

Mailman is a valuable addition for managing mailing lists. It enables users to subscribe and unsubscribe from lists, send emails to an entire list, and manage list archives.

3.1. Installing Mailman

Firstly, let’s install Mailman on the machine:

$ sudo apt install mailman

Secondly, let’s use the newlist command to create a new mailing list named mailman, which is necessary for setting up Mailman correctly:

$ sudo newlist mailman

During the process, we enter our personal email address and password for the list admin when prompted:

Enter the email of the person running the list:
Initial newsletter password:

After the process is complete, we start configuring Mailman.

3.2. Configuring Mailman

Let’s open the Mailman configuration file (/etc/mailman/mm_cfg.py) and edit two specific lines in it:

DEFAULT_EMAIL_HOST = 'example.com'
DEFAULT_URL_HOST = 'example.com'

The DEFAULT_EMAIL_HOST option specifies the default domain name used in the auto-generated email address of a newly created mailing list, which we’ll set to domain.com. So, if we then create a mailing list named newslist for example, its auto-generated email address will be [email protected].

The DEFAULT_URL_HOST option specifies the default domain name used in the web interface URL of a newly created mailing list, which we’ll also set to domain.com. This means the web interface URL for newslist will be https://domain.com/cgi-bin/mailman/listinfo/newslist.

Now, let’s insert domain.com as the value for both the options:

DEFAULT_EMAIL_HOST = 'domain.com'
DEFAULT_URL_HOST = 'domain.com'

After that, let’s create a new mailing list for the domain named mylist:

$ sudo newlist mylist

Here, we again provide our personal email address and password for the list admin. We’ll use this email address to send emails to this mailing list. Also, the auto-generated email address for this list will be [email protected].

Let’s note that Mailman mailing lists like the above operate on a per-list basis. This means the reach and membership of this list are specific to this list itself.

Upon creation, let’s open the /etc/aliases file and add some lines to it:

listname:              "|/usr/lib/mailman/mail/mailman post mylist"
listname-admin:        "|/usr/lib/mailman/mail/mailman admin mylist"
listname-bounces:      "|/usr/lib/mailman/mail/mailman bounces mylist"
listname-confirm:      "|/usr/lib/mailman/mail/mailman confirm mylist"
listname-join:         "|/usr/lib/mailman/mail/mailman join mylist"
listname-leave:        "|/usr/lib/mailman/mail/mailman leave mylist"
listname-owner:        "|/usr/lib/mailman/mail/mailman owner mylist"
listname-request:      "|/usr/lib/mailman/mail/mailman request mylist"
listname-subscribe:    "|/usr/lib/mailman/mail/mailman subscribe mylist"
listname-unsubscribe:  "|/usr/lib/mailman/mail/mailman unsubscribe mylist"

These aliases help perform different operations for the mailing list, such as managing user subscriptions, handling user requests, and more.

Once added, let’s run the newaliases command to update the alias database:

$ sudo newaliases

Finally, let’s run two more commands to get the utility up and running:

$ sudo systemctl start mailman
$ sudo systemctl enable mailman

We’re now done setting up Mailman on the machine.

3.3. Enabling the Web Interface

Mailman provides a web interface for performing mailing list operations. Let’s enable it by following some steps in order.

Firstly, let’s install the Apache web server on the machine, which is a useful tool for list configuration and management:

$ sudo apt install apache2

Then, let’s open the Apache configuration file (/etc/apache2/sites-available/000-default.conf) and add some lines to it:

ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
<Directory "/usr/lib/cgi-bin">
    AllowOverride None
    Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
    Require all granted
</Directory>

After that, let’s restart the services to implement the changes:

$ sudo systemctl restart apache2

Now, we can access the web interface by going to https://domain.com/cgi-bin/mailman/listinfo. For clarity, this web interface isn’t available on localhost. Also, this URL is a public URL that anyone can visit and perform user operations such as subscribing or unsubscribing to a mailing list shown in the interface.

However, we can go to the admin page, i.e., https://domain.com/cgi-bin/mailman/listinfo/admin to manage our lists as the admin. Others can also visit this page, but managing a particular mailing list requires the admin password set during the creation of that list. Hence, only we can manage our mailing lists. This ensures the security of the web interface.

4. Setting up Postfix

Postfix is responsible for sending and receiving emails. It manages incoming and outgoing mail connections, queuing emails, and routing them to their destinations.

Let’s learn how to connect Postfix to DKIM and Mailman on Ubuntu.

Before that, let’s install Postfix on the machine:

$ sudo apt install postfix

Now, let’s see how to connect DKIM to Postfix.

4.1. Connecting DKIM to Postfix

To integrate Postfix into OpenDKIM, let’s open the Postfix main configuration file (/etc/postfix/main.cf) and insert some lines in it:

milter_default_action = accept
milter_protocol = 2
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891

Let’s restart OpenDKIM and Postfix to apply the changes:

$ sudo systemctl restart opendkim
$ sudo systemctl restart postfix

Next, let’s connect Mailman to Postfix.

4.2. Connecting Mailman to Postfix

To integrate Postfix into Mailman, let’s again add some lines to the /etc/postfix/main.cf file:

alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
recipient_delimiter = +
mailman_destination_recipient_limit = 1

After saving the file, let’s open the /etc/postfix/master.cf file and append some lines to it:

mailman   unix  -       n       n       -       -       pipe
  flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
  ${nexthop} ${user}

Let’s restart Mailman and Postfix to apply the changes and complete connecting one to the other:

$ sudo systemctl restart mailman
$ sudo systemctl restart postfix

Let’s now test if all of them work together.

5. Testing

Firstly, let’s navigate to the mailing list web interface, i.e., https://domain.com/cgi-bin/mailman/listinfo:

Mailing List Web Interface

Here, we can see the newly created mailing list – mylist. Now, let’s click on the mylist link and put in an email address that we have access to ([email protected]) in the provided textbox to subscribe to the mailing list using the provided email.

Next, let’s send an email from our personal email address (that we used for configuring mylist) to [email protected]. If everything goes right, we’ll receive the email at [email protected] as it’s subscribed to the mylist mailing list. After receiving the email, we can say that Mailman and Postfix are working together successfully.

Now, let’s open the email received at [email protected] and click on the Show original button in the email options. Upon clicking, a new page shows up. Let’s notice a particular section in it:

DKIM Check

If we notice PASS in the value for the DKIM option, it means that the email is successfully signed by DKIM. This indicates that DKIM and Postfix are working together successfully.

6. Conclusion

In this article, we not only learned about the step-by-step process for installing and configuring DKIM, Postfix, and Mailman but also saw how they work together to create a secure email server.

Whether we’re system administrators or simply want to take control of our email communication, utilizing the combined power of these tools will enable us to build a secure and reliable email infrastructure.