Webmail using Roundcube
This feature is completely optional. If you are eager to get finished then skip this page and maybe come back later. You can still access your mail server using a mail user agent like Thunderbird.Power users may still want to use a mail client like Thunderbird. But most users nowadays seem to prefer reading their emails in the web browser. Let us install a web application for that purpose: Roundcube. Roundcube is the software that was also used in the previous versions of this guide. So, if your users are used to it… just stay with it.
Installation
Start by installing the software packages:sudo apt install -y roundcube roundcube-plugins roundcube-plugins-extra roundcube-mysql
Roundcube stores user settings in the database. So, you will get asked to set up database access.Choose Yes.
When asked for a password just press ENTER.Configure Apache
Do you remember that earlier in this guide I asked you how want to name your mail server? Whether you want to use one common name like “webmail.example.org” for all your domains? Or if you prefer different host names for each domain like “webmail.domain1.com” and “webmail.domain2.com”? If you want to use just more then you will have to create one virtual host configuration per domain. The following instructions will just deal with one common host name.To get Apache to serve the Roundcube application you need to edit the /etc/apache2/sites-available/webmail.example.org-https.conf file. I suggest you change the DocumentRoot line to:
DocumentRoot /var/lib/roundcube/public_html
All URLs are relative to that directory. So, if you go to https://webmail.example.com/ then files are looked up in that directory.Also add this line within the same VirtualHost section to add a couple of prepared security settings:
Include /etc/roundcube/apache.conf
And as usual Apache needs to be restarted after the configuration change:sudo systemctl restart apache2
Check that Apache is running properly:systemctl status apache2
In case of a problem run “sudo apache2ctl configtest” to find the cause.Limit access to localhost
The main configuration file of Roundcube is located at /etc/roundcube/config.inc.php. Feel free to customize the file. Fortunately, nowadays the basic settings are already as we need them. However, these two settings need to be changed by you:$config['default_host'] = ‘’;
$config['smtp_server'] = 'localhost';
For example, I changed them to:
$config[‘default_host’] = ‘localhost’;
$config[‘smtp_server’] = “tls://webmail.umd.me.uk”;
Restart apache2 server. Now when your users enter https://webmail.example.org/ in their browser they should get the Roundcube login form.
Keep in mind that we are using the email address as the account name of the user. So, when logging in please enter the email address as the user name. E.g., ‘john@example.org’ and password ‘summersun’.Plugins
Roundcube comes with various plugins that you can offer your users. I recommend at least these two:- password: Let the user change their access password.
- managesieve: Let the user manage rules that apply to incoming email. They can move mails to specific folders automatically for example.
$config['plugins'] = array(
'managesieve',
'password'
);
password plugin
Plugins are configured through files located in the /etc/roundcube/plugins directory. Let’s begin with the password plugin. Edit the /etc/roundcube/plugins/password/config.inc.php file.Oops, that file looks pretty empty. But it refers us to an example file at /usr/share/roundcube/plugins/password/config.inc.php.dist. There are many different methods to let users change their passwords. As we store that information in the SQL database, that is the part we need to set up.
Remove the empty definition line of $config from your config.inc.php file. Let’s go through the required settings one by one:- $config['password_driver'] = 'sql';
Simple. Use SQL as a backend. - $config['password_minimum_length'] = 12;
Allow no passwords shorter than 12 characters. I consider longer passwords more secure than short passwords with weird characters. You can even choose a larger minimum. - $config['password_force_save'] = true;
This will overwrite the password in the database even if it hasn’t changed. It helps us improve the strength of the password hash by re-encoding it with a better algorithm even if the user chooses to keep his old password. - $config['password_algorithm'] = 'blowfish-crypt';
The cryptographic algorithm to encode the password. This one is considered very secure and supported by Dovecot. - $config['password_algorithm_prefix'] = '{CRYPT}';
Prepend every password with this string so that Dovecot knows how we encrypted the password. - $config['password_db_dsn'] = 'mysql://mailadmin:E2zhrYD1156RtbPRgWLfU4uC0uCQ0g@localhost/mailserver';
Connection information for the local database. Use your own password for the mailadmin (!) database user here. We cannot use the restricted mailserver user because we have to write to the database if the user changes his password. - $config['password_query'] = "UPDATE virtual_users SET password=%P WHERE email=%u";
The SQL query that is run to write the new password hash into the database. %P is a placeholder for the new password hash. And %u is the logged-in user and conveniently matches the email address.
sudo chown root:www-data /etc/roundcube/plugins/password/config.inc.php
sudo chmod u=rw,g=r,o= /etc/roundcube/plugins/password/config.inc.php
sieve plugin
Sieve is a simple programming language to be used for server-side rules. Dovecot executes these rules every time a new email comes in. There are global rules that are executed for every email. And of course, every user/mailbox can have its own rules. To manage sieve rules Dovecot offers the managesieve interface that you enabled earlier. So, we just need to tell Roundcube how to access it.
The configuration file for Roundcube’s managesieve plugin is found at /etc/roundcube/plugins/managesieve/config.inc.php. This time just one setting is required to tell Roundcube which server to talk to:$config['managesieve_host'] = 'localhost';
Sieve rules are stored in a special syntax on the server. This is an example that moves all incoming emails to the test folder that have “test” in the subject:
require ["fileinto"];
if header :contains "subject" "test"
{
fileinto "INBOX/test";
}
You do not need to learn this syntax though. Roundcube’s sieve rule editor is way more user-friendly.
Try adding a sieve rule for john@example.org in Roundcube. That feature is located in Settings/Filters. You will find the machine-readable sieve code at /var/vmail/example.org/john/sieve/roundcube.sieve.
The rule editor looks like this:
0. Testing email delivery
So far you have spent considerable time with theory and configuration. Are you worried whether all you did actually leads to a working mail server? Before we do the final steps let’s take a break and verify that everything you did so far works as expected.You can get a list of all files and directories within by running:
sudo find /var/vmail
You may still get something along the lines of:
/var/vmail/umd.me.uk/sjin1239
/var/vmail/umd.me.uk/sjin1239/Maildir
/var/vmail/umd.me.uk/sjin1239/Maildir/cur
/var/vmail/umd.me.uk/sjin1239/Maildir/tmp
/var/vmail/umd.me.uk/sjin1239/Maildir/dovecot.list.index.log
/var/vmail/umd.me.uk/sjin1239/Maildir/dovecot-uidvalidity.6869d39b
/var/vmail/umd.me.uk/sjin1239/Maildir/dovecot.index.log
/var/vmail/umd.me.uk/sjin1239/Maildir/new
/var/vmail/umd.me.uk/sjin1239/Maildir/dovecot-uidlist
/var/vmail/umd.me.uk/sjin1239/Maildir/dovecot-uidvalidity
Basically, the schema you see here is /var/vmail/DOMAIN/USER/Maildir/…
Eeach IMAP mail folder has three subdirectories:- new – every file here is an email that was stored in this mail folder but not yet read
- cur – the same but for email that has been read already
- tmp – for temporary files from the mail server
Send a test email
It is time to send a new email into the system. Open a new terminal window and runtail -f /var/log/mail.log
to see what the mail server is doing. Now let’s send an email to sjin1239. My favorite tool for mail tests is swaks that you installed earlier. In the original terminal run:
swaks --to sjin1239@umd.me.uk --server localhost
If all works as expected, your mail.log will show a lot of technical information about the email delivery. Let me explain what happens at each stage.- postfix/smtpd[723766]: connect from localhost[::1]
Postfix receives an incoming SMTP connection. - postfix/smtpd[723766]: 4166D120109: client=localhost[::1]
Postfix assigns a unique identifier (4166D120109) to this connection so that you see which log lines belong together. This is especially important with busy mail servers where multiple mails are handled in parallel. - postfix/cleanup[723777]: 4166D120109: message-id=<20251109195732.723797@webmail.umd.me.uk>
swaks created a unique message id to the email which helps you identify specific mails in the log file. - postfix/qmgr[1437]: 4166D120109: from=<azureuser@webmail.umd.me.uk>, size=470, nrcpt=1 (queue active)
The sender was azureuser@webmail.umd.me.uk. This is logged after swaks sent the “MAIL FROM” line during the SMTP dialog. - postfix/smtpd[723766]: disconnect from localhost[::1] ehlo=1 mail=1 rcpt=1 data=1 quit=1 commands=5
The SMTP communication ends. Postfix has received and queued the email. - dovecot: lmtp(723801): Connect from local
Postfix connects to Dovecot to hand over the email via the LMTP interface. - dovecot: lmtp(sjin1239@umd.me.uk)<723801><AUhJESzyEGlZCwsATRJD4g>: msgid=<20251109195732.723797@webmail.umd.me.uk>: saved mail to INBOX
Dovecot received the email and stored his mailbox. - postfix/lmtp[723780]: 4166D120109: to=<sjin1239@umd.me.uk>, relay=webmail.umd.me.uk[private/dovecot-lmtp], delay=0.06, delays=0.01/0/0.01/0.04, dsn=2.0.0, status=sent (250 2.0.0 <sjin1239@umd.me.uk> AUhJESzyEGlZCwsATRJD4g Saved)
This is the one of the most interesting lines in your mail log. It tells you what happened with a certain email. In this case it says that it was handed over to dovecot-lmtp and that the delivery was successful (status=sent). The status codes like 2.0.0 are defined in RFC 3463 and work similar to status codes in HTTP. Codes beginning with ‘2’ are good. Those with ‘4’ are temporary errors. And ‘5’ stands for a permanent failure. - postfix/qmgr[1437]: 4166D120109: removed
The queue 4166D120109 was removed. - dovecot: lmtp(723801): Disconnect from local: Client has quit the connection (state=READY)
The LMTP connection between Postfix and Dovecot is closed.
If everything worked as expected Postfix has accepted the email and forwarded it to Dovecot which in turn wrote the email in sjin1239’s maildir.
Look again:sudo find /var/vmail
Dovecot has now created a directory structure for sjin1239 and created a new file:/var/vmail/
[…]
/var/vmail/umd.me.uk/sjin1239/Maildir/new/1762718252.M298981P723801.webmail.umd.me.uk,S=731,W=751
[…]
You can also use a slightly more comfortable tool to access Maildirs that will come handy for you as a mail server administrator: “mutt”.
sudo mutt -f /var/vmail/umd.me.uk/sjin1239/Maildir
What you see now are the contents of sjin1239’s mailbox:
Using mutt is a nice way to check mailboxes while you are logged in to the mail server.
To reiterate what happens when you receive an email:
- Postfix receives the email (using the “swaks” command in this example – but usually through the network using the SMTP protocol from other servers)
- Postfix talks to Dovecot via LMTP and hands over the email
- Dovecot runs through the user’s Sieve rules
- Dovecot writes the email file to disk
Accessing the email via IMAP (Roundcube)
Now that the email has been delivered you can talk to Dovecot using the IMAP protocol to retrieve your email again. Are you still logged in via the Roundcube webmail interface? Then just reload and you will see the email.