1.0 Introduction

This is the third in a series of six posts explaining how I set up an email server on CentOS 7. It will assume you’ve read the first and second articles in the series and taken the steps described there.

In this episode, we’ll be installing and configuring Dovecot. Where Postfix is responsible for receiving and sending email between mail servers (i.e., getting the mail to your server), Dovecot actually delivers received mail to specific inboxes of specific users on your server (and acts as an IMAP and POP server to let you read it from remote PCs). It’s the integration of Postfix and Dovecot that makes your mail server something you can actually interact with sensibly.

2.0 Configuring Dovecot

We actually installed Dovecot at the same time as we installed Postfix, back in Part 2. So all we have to do now is configure it to work properly. That can be quite a challenge, however!

For starters, let’s move the main Dovecot configuration file to a backup copy and then start editing a new, blank live copy:

mv /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf-backup
nano /etc/dovecot/dovecot.conf

Into the blank file, paste this lot:

protocols = imap pop3
log_timestamp = "%Y-%m-%d %H:%M:%S "
mail_location = maildir:/home/vmail/%d/%n/Maildir

ssl_cert = </etc/pki/dovecot/certs/dovecot.pem
ssl_key = </etc/pki/dovecot/private/dovecot.pem

namespace {
    type = private
    separator = .
    prefix = INBOX.
    #inbox = yes
}

service auth {
    unix_listener auth-master {
        mode = 0600
        user = vmail
    }

    unix_listener /var/spool/postfix/private/auth {
        mode = 0666
        user = postfix
        group = postfix
    }

user = root
}

service auth-worker {
    user = root
}

protocol lda {
    log_path = /home/vmail/dovecot-deliver.log
    auth_socket_path = /var/run/dovecot/auth-master
    postmaster_address = postmaster@dizwell.com
}

protocol pop3 {
    pop3_uidl_format = %08Xu%08Xv
}

passdb {
    driver = sql
    args = /etc/dovecot/dovecot-sql.conf.ext
}

userdb {
    driver = static
    args = uid=5000 gid=5000 home=/home/vmail/%d/%n allow_all_users=yes
}

!include conf.d/*.conf
!include_try local.conf

This tells Dovecot to act as an IMAP and POP3 server to start with; it also says where Dovecot should deliver email to -in this case, into subdirectories of the /home/vmail parent folder. Each user will have their own sub-directories within that parent folder.

The ssl lines in this file also tell Dovecot that we’re going to use self-signed certificates for making encryption work. This is OK for my purposes: I am not setting up a mail server that I expect hundreds of people to have accounts on, so trusting myself is not exactly difficult. It will mean, however, that when you first attempt to send or receive email via tools like Outlook or Thunderbird, you will be issued with dire-looking warnings about the mail server not being trustworthy. You will have to click through that when it happens. Otherwise, self-signing is fine if your needs are modest, as mine are.

Apart from that, most of the content in this configuration file just tells Dovecot administrative details, such as where to write its log file, what permissions to set on files and so on.

3.0 Setting up Dovecot to use MySQL

A further piece of Dovecot configuration is required to let it know how it can connect to and make use of the “mail” database we created back in part 2 of this series. That’s done by editing another configuration file, as follows:

nano /etc/dovecot/dovecot-sql.conf.ext

Into this new file, paste these contents:

driver = mysql
connect = host=127.0.0.1 dbname=mail user=mail_admin password=berrima1
default_pass_scheme = CRYPT
password_query = SELECT email as user, password FROM users WHERE email='%u';

That tells it that it will be connecting to a MySQL-type database; what the username and password are to connect correctly; and what the database name is when it gets there. Those username and password details are all as were originally specified back in part 2, remember. Finally, we give Dovecot a query it can execute in order to work out what an email user’s password is: when we try to connect to Dovecot to fetch our email, it will be important that it is able to authenticate us properly, after all!

Finally, make that new file accessible to the Dovecot user:

chgrp dovecot /etc/dovecot/dovecot-sql.conf.ext
chmod o= /etc/dovecot/dovecot-sql.conf.ext

4.0 Testing it works

We are now in a position to make sure that the Dovecot components are working and configured correctly. First, we have to make sure that we can telnet internally to the various ports that the two applications are going to be managing for us:

yum -y install telnet-server telnet
systemctl start telnet.socket
systemctl restart postfix dovecot

Once telnet exists and Postfix and Dovecot have been switched on, you can try this:

telnet localhost pop3

You should receive a message saying “OK Dovecot ready” -and if you do, then you can type quit to exit the telnet console.

You can also test Postfix in the same sort of way:

telnet localhost 25

When the thing connects correctly, you can type:

ehlo localhost

…and by way of reply, you should see this:

250-mail.dizwell.com
250-PIPELINING
250-SIZE 30720000
250-VRFY
250-ETRN
250-STARTTLS            
250-AUTH PLAIN
250-AUTH=PLAIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN

It’s important that you see the STARTTLS line I’ve put in bold there: it means that Postfix is correctly able to handle encrypted connections. If it all looks good, just type quit to exit once more. I would then suggest issuing these commands:

yum -y remove telnet-server telnet

Telnet being a very insecure service, you do not want it running on your real email server for any longer than strictly necessary!

5.0 Creating Mail Aliases

It’s a minor piece of housekeeping, but it’s important that Dovecot knows how to handle email which may be received addressed to some standard accounts that might not actually exist. For example, “postmaster@dizwell.com”… which real user should receive that account’s email?

We therefore create mappings between generic accounts and real ones, called mail aliases.

nano /etc/aliases

At the very end of the file, add this entry

root: postmaster@dizwell.com

Then finish up by getting the system aware of the existence of a new entry in the alias file:

newaliases
systemctl restart postfix

6.0 Create an email account

The last thing to do before trying to test our new setup is to create an account that can receive email. You do that by inserting records into one of the MySQL tables, like so:

mysql -u root -p
use mail;
insert into domains (domain) VALUES ('dizwell.com');
insert into users (email, password) VALUES ('hjr@dizwell.com', ENCRYPT('donbplonker'));
quit

It’s a simple enough couple of inserts: which domain the account is for, and then the account name and (encrypted) password. (I hasten to add that’s not my real password!)

Note that this is how you will create additional email accounts for your spouse, beloved or significant other, too.

7.0 Configuring your Domain records properly

Before we can go any further, you now have to make sure that your domain’s MX records point to your new server. Everything up to this point could be done on your server without the outside world knowing about it, but now we need to resolve things correctly. For me, this means that “mail.dizwell.com” has to point to my server at 163.172.162.195 and that my domain registry has an MX record that resolves to mail.dizwell.com.

Explaining how this is done is a bit outside the scope of this article, because it depends very much on your domain registrar and what else you do with your domain registration records! In my case, for example, my domain registrar is a slightly dodgy Australian outfit called “crazydomains”. Their record of my dizwell.com domain looks as follows:

crazy01

My domain name is resolved into specific IP addresses not by asking Crazydomains about it, but by further asking one of a couple of servers living at cloudflare.com. Note that Crazydomains knows nothing about MX records, either: that stuff is again handled by Cloudflare.

So you have to ask Cloudflare about my domain:

cloud01

Cloudflare knows to find dizwell.com at 163.172.42.97 -that’s my physical web server in Paris. But it also knows to resolve mail.dizwell.com to 163.172.162.195 (which is my second physical server in Paris).

And then there are my many MX records! Up to this point, of course, I’ve wanted my email to work without interruption… so there are three MX records which indicate, in various orders of preference, that several email servers at zoho.com are to handle any email addressed to ‘dizwell.com’. It’s that which now has to change: and you can see I’ve added a new MX record with a priority of ‘1’ (making it take precedence over all the zoho.com ones) that says ‘anything addressed to <someone>@dizwell.com’ should be handled by “mail.dizwell.com” …and the second A record shows, as discussed, that that means “by server 163.172.162.195”.

It’s quite complex -and not everyone will have the extra layer of indirection caused by cacheing one’s content behind Cloudflare’s proxy servers!

But the general point is that you now need to be able to resolve your ‘mail.domain.com’ address to your new email server’s public IP address; and you need an MX record which takes precedence over any others you might have that says email addressed to ‘domain.com’ shall be sent to the ‘mail.domain.com’ server. The new A and MX records work in tandem to make your mail deliverable at your new server, basically.

Remember, too, that changes to your domain’s DNS records tend to take some time to propagate around the Interwebs. Don’t add a new A and MX record and expect everything to work instantly, basically. (I will say, though, that changes made at Cloudflare [in the US] do seem to take effect in Australia within minutes, which is one reason I like them a lot!)

8.0 Putting it to the test

If your DNS records are fine, then you can put your new email server to the test. First, an ‘internal’ test:

yum -y install mailx

Mailx is a lightweight mailing program you can use directly on the mail server itself. Once it’s installed, just type:

mailx hjr@dizwell.com

Type a subject and some body text when prompted and press Ctrl+D when you’re finished. The whole thing might look as follows:

[root@mail conf]# mailx hjr@dizwell.com
Subject: Test Email
Here is a test email
EOT

Now, to see if that worked, check the contents of /var/log/maillog and /home/vmail/dovecot-deliver.log. In maillog, for example, you should see lines like:

Jun 17 17:43:32 mail postfix/cleanup[23897]: 9756518045E: message-id=<20160617074332.9756518045E@mail.dizwell.com>
Jun 17 17:43:32 mail postfix/qmgr[16471]: 9756518045E: from=<root@mail.dizwell.com>, size=449, nrcpt=1 (queue active)
Jun 17 17:43:32 mail postfix/pipe[23905]: 9756518045E: to=<hjr@dizwell.com>, relay=dovecot, delay=0.21, delays=0.1/0.02/0/0.1, dsn=2.0.0, status=sent (delivered via dovecot service)
Jun 17 17:43:32 mail postfix/qmgr[16471]: 9756518045E: removed

…which indicates that my test message from root was successfully delivered to ‘hjr@dizwell.com’.

How can hjr see his new email? Well, he can’t as yet but root can do this:

yum -y install mutt
cd /home/vmail/dizwell.com/hjr/Maildir
mutt -f .

You’ll be prompted to create a mailbox for root: say ‘no’ to that. You should then see something like this:

mutt01

…which is hjr’s inbox being displayed locally, with the test email successfully delivered. (Type ‘q’ -potentially a number of times, depending on where you’ve got to- to quit out of mutt, by the way!)

If that worked well enough, then you can use an external email account you might have at Gmail, Outlook or something else to send an email to hjr@dizwell.com… Again, using mutt on the server itself, you should find that gets delivered OK too.

So, at this point you have successfully built yourself a working mail server. New users can be created with a bit of SQL; email can be sent and received. Job done? Hardly: the initial requirement was for a mail server with webmail capability, and our current effort lacks any of that. It is also wide open to abusive spam and virus-laden email. So there are some things to bolt on to this very basic framework before we can be entirely happy… but it’s a start.

9.0 Conclusion

With a mail server capable of sending and receiving email, that’s a good place to end this particular episode of the ‘build your own mail server’ series. In the next article, I’ll show how to add the Roundcube web application to your server and thus give you a convenient interface to handle your emailing needs.