Part 3: PostfixAdmin – Create Virtual Mailboxes on Ubuntu 20.04 Mail Server

In previous articles, we discussed how to set up your own mail server on Ubuntu from scratch. In part 1 and part 2 of this tutorial series, we learned how to set up Postfix SMTP server and Dovecot IMAP server, but so far we can only have email addresses for users with local Unix accounts. This tutorial is going to show you how to create virtual mailboxes on Ubuntu 20.04 mail server with PostfixAdmin, which is an open-source web-based interface to configure and manage a Postfix based email server for many domains and users.

With virtual mailboxes, we don’t need to create a local Unix account for each email address. If you are going to set up a mail server for a company or organization, it’s always better to have an easy way to create virtual mailboxes in a web-based interface, which also allows users to change their passwords. That’s where PostfixAdmin comes in.

PostfixAdmin Features

  • manage mailboxes, virtual domains and aliases
  • vacation/out-of-office messages
  • alias domains (forwarding one domain to another with recipient validation)
  • users can manage their own mailbox (change alias, password and vacation message)
  • quota support for single mailboxes and total quota of a domain
  • display used quota
  • fetchmail integration: You can fetch emails from your original email address to your new email address.
  • command line client postfixadmin-cli for those who don’t want to click around in a web interface 😉

Note: Once you finish part 3, you can no longer use local Unix accounts as email addresses. You must create email addresses from the PostfixAdmin web interface.

Prerequisites

It’s required that you have followed part 1 and part 2 of this tutorial series before continuing reading this article. If you followed mail server tutorials on other websites, I recommend purging your configurations and start over with my tutorial series, so you are not going to be confused by different setup processes.

PostfixAdmin is written in PHP and requires a database (MySQL/MariaDB, PostgreSQL or SQLite). This article will use MariaDB database. You also need to run Apache or Nginx web server. So basically we are going to need a LAMP or LEMP stack.

If you prefer to use Apache web server, then set up a LAMP stack.

If you prefer to use Nginx web server, then set up a LEMP stack.

Once the above requirements are met, let’s install and configure PostfixAdmin.

Step 1: Install PostfixAdmin on Ubuntu 20.04 Server

Log into your mail server. Because some readers use MariaDB server, while others use MySQL, which makes things complicated, so before installing PostfixAdmin, we install the dbconfig-no-thanks package to prevent the postfixadmin package from launching the database configure wizard.

sudo apt install dbconfig-no-thanks

Then install PostfixAdmin from the default Ubuntu software repository.

sudo apt install postfixadmin
Note: If you have previously installed mysql-server on Ubuntu, the installation of PostfixAdmin will probably remove the mysql-server package from your system. You can re-install it by running the following command.

sudo apt install mysql-server

Now we need to remove the dbconfig-no-thanks package.

sudo apt remove dbconfig-no-thanks

Then launch the database configure wizard for PostfixAdmin.

sudo dpkg-reconfigure postfixadmin

During the installation, you will be asked if you want to reinstall database for PostfixAdmin. Press the Tab key to choose Yes.

reinstall databae for postfixadmin

Then select the default database type: mysql, if you use MySQL or MariaDB.

postfixadmin mariadb mysql

Next, choose the default connection method: Unix socket.

postfixadmin connection method for mysql

Then choose the default authentication plugin for MySQL/MariaDB.

postfixadmin authentication plugin for MySQL MariaDB

Press Enter to choose the default database name for PostfixAdmin.

postfixadmin ubuntu 20.04 LTS

Press Enter to choose the default database username for PostfixAdmin.

database username for PostfixAdmin

After that, you need to set a password for this user. Note that the password should not contain the # character, or you might not be able to log in later.

postfixadmin database password
Finally, choose the default database administrative user.

postfixadmin database administrative user

After PostfixAdmin is installed, you can log in to MySQL/MariaDB console with the following command. You will need to enter the password for the postfixadmin user.

mysql -u postfixadmin -p

And you can check what databases the user has permissions to access with the following command.

SHOW DATABASES;

Output:

+--------------------+
| Database           |
+--------------------+
| information_schema |
| postfixadmin       |
+--------------------+
2 rows in set (0.002 sec)

By default, the postfixadmin database contains no tables. You can log out of the MySQL/MariaDB console with the following command.

EXIT;

The installation will also create two configuration files: /etc/dbconfig-common/postfixadmin.conf and /etc/postfixadmin/dbconfig.inc.php, both of which contain the database access settings, including the database username and password. We need to change the database type from mysql to mysqli in both of the two files.

sudo nano /etc/dbconfig-common/postfixadmin.conf

Change

dbc_dbtype='mysql'

to

dbc_dbtype='mysqli'

Then edit the second file.

sudo nano /etc/postfixadmin/dbconfig.inc.php

Change

$dbtype='mysql';

to

$dbtype='mysqli';

The web files are installed under /usr/share/postfixadmin/ directory, which is owned by root. PostfixAdmin requires a templates_c directory, so create it.

sudo mkdir /usr/share/postfixadmin/templates_c

We need to give www-data user read, write and execute permissions on this directory with the following command.

sudo setfacl -R -m u:www-data:rwx /usr/share/postfixadmin/templates_c/

If your system can’t find the setfacl command, you need to install the acl package.

sudo apt install acl

Step 2: Create Apache Virtual Host or Nginx Config File for PostfixAdmin

Apache

If you use Apache web server, create a virtual host for PostfixAdmin.

sudo nano /etc/apache2/sites-available/postfixadmin.conf

Put the following text into the file. Replace postfixadmin.example.com with your real domain name and don’t forget to set DNS A record for it.

<VirtualHost *:80>
  ServerName postfixadmin.example.com
  DocumentRoot /usr/share/postfixadmin/public

  ErrorLog ${APACHE_LOG_DIR}/postfixadmin_error.log
  CustomLog ${APACHE_LOG_DIR}/postfixadmin_access.log combined

  <Directory />
    Options FollowSymLinks
    AllowOverride All
  </Directory>

  <Directory /usr/share/postfixadmin/>
    Options FollowSymLinks MultiViews
    AllowOverride All
    Order allow,deny
    allow from all
  </Directory>

</VirtualHost>

Save and close the file. Then enable this virtual host with:

sudo a2ensite postfixadmin.conf

Reload Apache for the changes to take effect.

sudo systemctl reload apache2

Now you should be able to see the PostfixAdmin web-based install wizard at http://postfixadmin.example.com/setup.php.

Nginx

If you use Nginx web server, create a virtual host for PostfixAdmin.

sudo nano /etc/nginx/conf.d/postfixadmin.conf

Put the following text into the file. Replace postfixadmin.example.com with your real domain name and don’t forget to set DNS A record for it.

server {
   listen 80;
   listen [::]:80;
   server_name postfixadmin.example.com;

   root /usr/share/postfixadmin/public/;
   index index.php index.html;

   access_log /var/log/nginx/postfixadmin_access.log;
   error_log /var/log/nginx/postfixadmin_error.log;

   location / {
       try_files $uri $uri/ /index.php;
   }

   location ~ ^/(.+\.php)$ {
        try_files $uri =404;
        fastcgi_pass unix:/run/php/php7.4-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include /etc/nginx/fastcgi_params;
   }
}

Save and close the file. Then test Nginx configuration.

sudo nginx -t

If the test is successful, reload Nginx for the changes to take effect.

sudo systemctl reload nginx

Now you should be able to see the PostfixAdmin web-based install wizard at http://postfixadmin.example.com/setup.php.

Step 3: Install Required and Recommended PHP Modules

Run the following command to install PHP modules required or recommended by PostfixAdmin.

sudo apt install php7.4-fpm php7.4-imap php7.4-mbstring php7.4-mysql php7.4-json php7.4-curl php7.4-zip php7.4-xml php7.4-bz2 php7.4-intl php7.4-gmp

Then restart Apache. (If you use Nginx, you don’t need to restart Nginx.)

sudo systemctl restart apache2

Step 4: Enabling HTTPS

To encrypt the HTTP traffic, we can enable HTTPS by installing a free TLS certificate issued from Let’s Encrypt. Run the following command to install Let’s Encrypt client (certbot) on Ubuntu 20.04 server.

sudo apt install certbot

If you use Apache, install the Certbot Apache plugin.

sudo apt install python3-certbot-apache

And run this command to obtain and install TLS certificate.

sudo certbot --apache --agree-tos --redirect --hsts --staple-ocsp --email [email protected] -d postfixadmin.example.com

If you use Nginx, then you also need to install the Certbot Nginx plugin.

sudo apt install python3-certbot-nginx

Next, run the following command to obtain and install TLS certificate.

sudo certbot --nginx --agree-tos --redirect --hsts --staple-ocsp --email [email protected] -d postfixadmin.example.com

Where

  • --nginx: Use the nginx plugin.
  • --apache: Use the Apache plugin.
  • --agree-tos: Agree to terms of service.
  • --redirect: Force HTTPS by 301 redirect.
  • --hsts: Add the Strict-Transport-Security header to every HTTP response. Forcing browser to always use TLS for the domain. Defends against SSL/TLS Stripping.
  • --staple-ocsp: Enables OCSP Stapling. A valid OCSP response is stapled to the certificate that the server offers during TLS.

The certificate should now be obtained and automatically installed, which is indicated by the message below.

postfixadmin ubuntu https

Step 5: Use Strong Password Scheme in PostfixAdmin and Dovecot

By default, PostfixAdmin and Dovecot use MD5-CRYPT, which is a weak password scheme. You can list available password schemes in Dovecot with the following command.

sudo doveadm pw -l

Sample output:

SHA1 SSHA512 BLF-CRYPT PLAIN HMAC-MD5 OTP SHA512 SHA RPA DES-CRYPT CRYPT SSHA MD5-CRYPT SKEY PLAIN-MD4 PLAIN-MD5 SCRAM-SHA-1 LANMAN SHA512-CRYPT CLEAR CLEARTEXT ARGON2I ARGON2ID SSHA256 NTLM MD5 PBKDF2 SHA256 CRAM-MD5 PLAIN-TRUNC SHA256-CRYPT SMD5 DIGEST-MD5 LDAP-MD5

Argon2 is a fairly strong password scheme. To use it, we need to edit the PostfixAdmin configuration file, which by default is /usr/share/postfixadmin/config.inc.php, but we can create a separate file (config.local.php) to store our modifications, so they won’t be overriden when a new version of PostfixAdmin is installed in the future.

sudo nano /usr/share/postfixadmin/config.local.php

Add the following lines in the file to use Argon2 password scheme.

<?php
$CONF['encrypt'] = 'dovecot:ARGON2I';

$CONF['dovecotpw'] = "/usr/bin/doveadm pw -r 5";
if(@file_exists('/usr/bin/doveadm')) { // @ to silence openbase_dir stuff; see https://github.com/postfixadmin/postfixadmin/issues/171
    $CONF['dovecotpw'] = "/usr/bin/doveadm pw -r 5"; # debian
}

Save and close the file. We can also create a symlink in the /etc/postfixadmin/ directory, just in case PostfixAdmin can’t find the file.

sudo ln -s /usr/share/postfixadmin/config.local.php /etc/postfixadmin/config.local.php

We will configure password scheme for Dovecot in step 9.

Step 6: Finish the Installation in Web Browser

Go to postfixadmin.example.com/setup.php to run the web-based setup wizard. First, it will check if all dependencies are installed.

ubuntu 20.04 postfixadmin setup checker

If you see the following error,

Invalid query: Specified key was too long; max key length is 1000 bytes

Then you need to log in to MySQL/MariaDB database server as root from command line,

sudo mysql -u root

and change the default collation from utf8mb4_general_ci to utf8_general_ci.

MariaDB [(none)]> alter database postfixadmin collate ='utf8_general_ci';

Exit MySQL/MariaDB console and reload the setup.php page. Once all requirements are satisfied, you can create a setup password for PostfixAdmin.

postfixadmin virtual domain

After creating the password hash, you need to open the /usr/share/postfixadmin/config.local.php file and add the setup password hash at the end of the file like below. Of course, you need to use your own password hash.

postfixadmin setup password

Next, create the admin account.

postfixadmin ubuntu install

After that, you can log into PostfixAdmin at postfixadmin.example.com/login.php.

postfixadmin virtual mailbox domains

Step 7: Checking Tables in the Database

The PostfixAdmin setup process populates the postfixadmin database with some default tables. It’s helpful for us to know the names and structure of the tables. Log in to MySQL/MariaDB console.

sudo mysql -u root

Select the postfixadmin database.

USE postfixadmin;

List all tables in this database.

SHOW TABLES;

Output:

+------------------------+
| Tables_in_postfixadmin |
+------------------------+
| admin                  |
| alias                  |
| alias_domain           |
| config                 |
| domain                 |
| domain_admins          |
| fetchmail              |
| log                    |
| mailbox                |
| quota                  |
| quota2                 |
| vacation               |
| vacation_notification  |
+------------------------+
13 rows in set (0.001 sec)

The 3 most important tables are:

  • domain: contains information on the domains that are using your mail server to send and receive email.
  • mailbox: contains information on every email address, including hashed password and the location of mail files.
  • alias: contains the alias of each email address.

If you are interested, you can check what columns each table contains. For example, the following command will show us the columns in the domain table.

DESCRIBE domain;

Output:

+-------------+--------------+------+-----+---------------------+-------+
| Field       | Type         | Null | Key | Default             | Extra |
+-------------+--------------+------+-----+---------------------+-------+
| domain      | varchar(255) | NO   | PRI | NULL                |       |
| description | varchar(255) | NO   |     | NULL                |       |
| aliases     | int(10)      | NO   |     | 0                   |       |
| mailboxes   | int(10)      | NO   |     | 0                   |       |
| maxquota    | bigint(20)   | NO   |     | 0                   |       |
| quota       | bigint(20)   | NO   |     | 0                   |       |
| transport   | varchar(255) | NO   |     | NULL                |       |
| backupmx    | tinyint(1)   | NO   |     | 0                   |       |
| created     | datetime     | NO   |     | 2000-01-01 00:00:00 |       |
| modified    | datetime     | NO   |     | 2000-01-01 00:00:00 |       |
| active      | tinyint(1)   | NO   |     | 1                   |       |
+-------------+--------------+------+-----+---------------------+-------+

Log out of MySQL/MariaDB console.

EXIT;

Step 8: Configure Postfix to Use MySQL/MariaDB Database

By default, Postfix delivers emails only to users with a local Unix account. To make it deliver emails to virtual users whose information is stored in the database, we need to configure Postfix to use virtual mailbox domains.

First, we need to add MySQL map support for Postfix by installing the postfix-mysql package.

sudo apt install postfix-mysql

Then edit the Postfix main configuration file.

sudo nano /etc/postfix/main.cf

Add the following lines at the end of this file.

virtual_mailbox_domains = proxy:mysql:/etc/postfix/sql/mysql_virtual_domains_maps.cf
virtual_mailbox_maps =
   proxy:mysql:/etc/postfix/sql/mysql_virtual_mailbox_maps.cf,
   proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_mailbox_maps.cf
virtual_alias_maps =
   proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_maps.cf,
   proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_maps.cf,
   proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_catchall_maps.cf

Where:

  • virtual_mailbox_domains points to a file that will tell Postfix how to look up domain information from the database.
  • virtual_mailbox_maps points to files that will tell Postfix how to look up email addresses from the database.
  • virtual_alias_maps points to files that will tell Postfix how to look up aliases from the database.

We want to use dovecot to deliver incoming emails to the virtual users’ message store, so also add the following line at the end of this file.

virtual_transport = lmtp:unix:private/dovecot-lmtp

Configure-Postfix-to-Use-MySQL-MariaDB-Database-ubuntu

Save and close the file. Next, we need to create the .cf files one by one. Create the sql directory.

sudo mkdir /etc/postfix/sql/

Create the mysql_virtual_domains_maps.cf file.

sudo nano /etc/postfix/sql/mysql_virtual_domains_maps.cf

Add the following content. Replace password with the postfixadmin password you set in Step 1.

user = postfixadmin
password = password
hosts = localhost
dbname = postfixadmin
query = SELECT domain FROM domain WHERE domain='%s' AND active = '1'
#query = SELECT domain FROM domain WHERE domain='%s'
#optional query to use when relaying for backup MX
#query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = '0' AND active = '1'
#expansion_limit = 100

Create the mysql_virtual_mailbox_maps.cf file.

sudo nano /etc/postfix/sql/mysql_virtual_mailbox_maps.cf

Add the following content.

user = postfixadmin
password = password
hosts = localhost
dbname = postfixadmin
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = '1'
#expansion_limit = 100

Create the mysql_virtual_alias_domain_mailbox_maps.cf file.

sudo nano /etc/postfix/sql/mysql_virtual_alias_domain_mailbox_maps.cf

Add the following content.

user = postfixadmin
password = password
hosts = localhost
dbname = postfixadmin
query = SELECT maildir FROM mailbox,alias_domain WHERE alias_domain.alias_domain = '%d' and mailbox.username = CONCAT('%u', '@', alias_domain.target_domain) AND mailbox.active = 1 AND alias_domain.active='1'

Create the mysql_virtual_alias_maps.cf file.

sudo nano /etc/postfix/sql/mysql_virtual_alias_maps.cf

Add the following content.

user = postfixadmin
password = password
hosts = localhost
dbname = postfixadmin
query = SELECT goto FROM alias WHERE address='%s' AND active = '1'
#expansion_limit = 100

Create the mysql_virtual_alias_domain_maps.cf file.

sudo nano /etc/postfix/sql/mysql_virtual_alias_domain_maps.cf

Add the following content.

user = postfixadmin
password = password
hosts = localhost
dbname = postfixadmin
query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = CONCAT('%u', '@', alias_domain.target_domain) AND alias.active = 1 AND alias_domain.active='1'

Create the mysql_virtual_alias_domain_catchall_maps file.

sudo nano /etc/postfix/sql/mysql_virtual_alias_domain_catchall_maps.cf

Add the following content.

# handles catch-all settings of target-domain
user = postfixadmin
password = password
hosts = localhost
dbname = postfixadmin
query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = CONCAT('@', alias_domain.target_domain) AND alias.active = 1 AND alias_domain.active='1'

Since the database passwords are stored in plain text so they should be readable only by user postfix and root, which is done by executing the following two commands.

sudo chmod 0640 /etc/postfix/sql/*
sudo setfacl -R -m u:postfix:rx /etc/postfix/sql/

Next, we need to change the value of the mydestination parameter in Postfix. Display the current value:

postconf mydestination

Sample output:

mydestination = $myhostname, linuxbabe.com, localhost.$mydomain, localhost

The mydestination parameter contains a list of domain names that will receive emails delivered to local Unix accounts. In part 1, we added the apex domain name (like linuxbabe.com) to mydestination. Since we are going to use virtual mailbox, we need to remove the apex domain name from the list by issuing the following command.

sudo postconf -e "mydestination = \$myhostname, localhost.\$mydomain, localhost"

Now let’s open the Postfix main configuration file again.

sudo nano /etc/postfix/main.cf

Add the following lines at the end of this file.

virtual_mailbox_base = /var/vmail
virtual_minimum_uid = 2000
virtual_uid_maps = static:2000
virtual_gid_maps = static:2000

The first line defines the base location of mail files. The remaining 3 lines define which user ID and group ID Postfix will use when delivering incoming emails to the mailbox. We use the user ID 2000 and group ID 2000.

Save and close the file. Restart Postfix for the changes to take effect.

sudo systemctl restart postfix

Next, we need to create a user named vmail with ID 2000 and a group with ID 2000.

sudo adduser vmail --system --group --uid 2000 --disabled-login --no-create-home

Create the mail base location.

sudo mkdir /var/vmail/

Make vmail as the owner.

sudo chown vmail:vmail /var/vmail/ -R

Step 9: Configure Dovecot to Use MySQL/MariaDB Database

We also need to configure the Dovecot IMAP server to query user information from the database. First, run the following command to add MySQL support for Dovecot.

sudo apt install dovecot-mysql

Then edit the 10-mail.conf file.

sudo nano /etc/dovecot/conf.d/10-mail.conf

In part 2, we used the following mail_location. Email messages are stored under the Maildir directory under each user’s home directory.

mail_location = maildir:~/Maildir

Since we are using virtual mailbox domain now, it’s a good practice to store emails under /var/vmail/example.com/username/, so change the mail_location to:

mail_location = maildir:/var/vmail/%d/%n

It’s recommended to enable mail_home for the virtual users by adding the following line in the file, because virtual users don’t have home directories by default.

mail_home = /var/vmail/%d/%n

Save and close the file. Then edit the 10-auth.conf file.

sudo nano /etc/dovecot/conf.d/10-auth.conf

In part 2, we used the following value for auth_username_format.

auth_username_format = %n

The %n would drop the domain if it was given. Because in part 2 we were using local Unix account for the username of every email address, we must use %n to drop the domain, so users were able to login with the full email address.

Now we are using virtual mailbox domains, which means the username of every email address includes the domain part, so we need to change the auth_username_format as follows. %u won’t drop away the domain. This allows users to login with the full email address.

auth_username_format = %u

Uncomment the following line at the end of this file, so Dovecot can query user information from MySQL/MariaDB database.

!include auth-sql.conf.ext

Now you probably don’t want local Unix users to send emails without registering email addresses in PostfixAdmin, then comment out the following line by adding the # character at the beginning, so Dovecot won’t query the local /etc/passwd or /etc/shadow file.

#!include auth-system.conf.ext

It can be helpful to add the following two lines in this file to debug login issues. The login errors would be logged into /var/log/mail.log file. (Once users can login without problems, you can comment out the following two lines.)

auth_debug = yes
auth_debug_passwords = yes

dovecot mysql Password database

Save and close the file.

Edit the dovecot-sql.conf.ext file.

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

Here is the content that you should have. Replace password with the postfixadmin password you set in Step 1.

driver = mysql

connect = host=localhost dbname=postfixadmin user=postfixadmin password=password

default_pass_scheme = ARGON2I

password_query = SELECT username AS user,password FROM mailbox WHERE username = '%u' AND active='1'

user_query = SELECT maildir, 2000 AS uid, 2000 AS gid FROM mailbox WHERE username = '%u' AND active='1'

iterate_query = SELECT username AS user FROM mailbox

Restart Dovecot.

sudo systemctl restart dovecot

When a user tries to log in, Dovecot would use the Argon2 algorithm to generate a password hash from the password entered by the user, then compare it with the password hash stored in the database.

Step 10: Add Domain and Mailboxes in PostfixAdmin

Log in to PostfixAdmin web interface as the admin. Click the Domain List tab and select New Domain to add a domain. You can choose how many aliases and mailboxes are allowed for this domain.

postfixadmin add domain

Then click Virtual List tab and select Add Mailbox to add a new email address for your domain.

postfixadmin add mailbox

Next, you can open your desktop email client such as Mozilla Thunderbird and add a mail account.

  • In the incoming server section, select IMAP protocol, enter mail.your-domain.com as the server name, choose port 143 and STARTTLS. Choose normal password as the authentication method.
  • In the outgoing section, select SMTP protocol, enter mail.your-domain.com as the server name, choose port 587 and STARTTLS. Choose normal password as the authentication method.

modoboa-mail-server-desktop-mail-client-configuration-automx

You should now be able to connect to your own email server and also send and receive emails with your desktop email client! Note that you cannot use local Unix accounts to login now. You must log in with the virtual user created from PostfixAdmin web interface.

Troubleshooting Tips

If you can’t log into your mail server from a desktop mail client, scan your mail server to find if the ports are open. Note that you should run the following command from another Linux computer or server. If you run it on your mail server, then the ports will always appear to be open.

sudo nmap mail.example.com

And check if Dovecot is running.

systemctl status dovecot

You can also check the mail log (/var/log/mail.log), which may give you some clues.

Automatically Clean the Junk Folder and Trash Folder

To delete emails in Junk folder for all users, you can run

sudo doveadm expunge -A mailbox Junk all

To delete emails in Trash folder, run

sudo doveadm expunge -A mailbox Trash all

I think it’s better to clean emails that have been in the Junk or Trash folder for more than 2 weeks, instead of cleaning all emails.

sudo doveadm expunge -A mailbox Junk savedbefore 2w

Then add a cron job to automate the job.

sudo crontab -e

Add the following line to clean Junk and Trash folder every day.

@daily doveadm expunge -A mailbox Junk savedbefore 2w;doveadm expunge -A mailbox Trash savedbefore 2w

To receive report when a Cron job produces an error, you can add the following line above all Cron jobs.

MAILTO="[email protected]"

Save and close the file. And you’re done.

Change User Password in PostfixAdmin

Users can log into PostfixAdmin at https://postfixadmin.example.com/users/login.php, then change their passwords.

Next Step

I hope this tutorial helped you install and use PostfixAdmin on Ubuntu 20.04 to create virtual mailboxes. In part 4, I will show you how to set up SPF and DKIM with Postfix to improve email deliverability and in a future tutorial, I’m going to show you how to host multiple domains with PostfixAdmin.

If you want to access emails from a web browser, then I recommend Roundcube, which is a very popular and featured-rich open-source webmail client. As always, if you found this post useful,  subscribe to our free newsletter to get more tips and tricks. Take care 🙂

Rate this tutorial
[Total: 5 Average: 5]

55 Responses to “Part 3: PostfixAdmin – Create Virtual Mailboxes on Ubuntu 20.04 Mail Server

  • Quang Mai
    3 months ago

    Hi Xiao,

    Thanks for this part 3 of the Email Server. I have followed Part 1 and 2.

    I’m new with Email server so just to confirm that I can start a fresh server and install this Part 3 to use Email Server with PostfixAdmin. And following installation from Part 4 – Part 9 for a EMAIL SERVER PRODUCTION?

    Can we both install Postfix and PostfixAdmin as follow the full installation from Part1 – Part9 as this site: “https://www.linuxbabe.com/mail-server/setup-basic-postfix-mail-sever-ubuntu”?

    Thanks so much.
    Kind regards,
    Quang

    • In the “prerequisites” section of this article, there’s a sentence: “It’s required that you have followed part 1 and part 2 of this tutorial series before continuing reading this article.”

      • Quang Mai
        3 months ago

        Hi Xiao,

        Thanks so much for the reply. Yes, I followed till nearly the end of Part 2.

        However, I still couldn’t setup the email account with ThunderBird for both user1 & user2. Do not know what I did wrong. I am very careful with your detail instructions with step by step following.

        It says: “Thunderbird failed to find the settings for your email account.” I also tried the other Port 993 & 465 with normal password as the Unix Password.

        Should I just continue to the Cronjob part at the last session and go on to Part 3 with the virtual Mailbox? Feeling stuck here!

        Much appreciated for your support.

    • Can you tell me what’s your domain name? If you don’t like to show your domain name in public, you can reply in email.

    • First, you MX record is wrong. You should create MX for your apex domain name like below.
      MX record
      Second, only port 22, 80 and 443 on your server are open.

      Not shown: 997 filtered ports
      PORT    STATE SERVICE
      22/tcp  open  ssh
      80/tcp  open  http
      443/tcp open  https
      
      Nmap done: 1 IP address (1 host up) scanned in 11.68 seconds
      
  • Quang Mai
    3 months ago

    Hi Xiao,

    All working good now. Thanks so much. Learning new stuff every day by making a mistake!!!

  • Quang Mai
    3 months ago

    Hello Xiao,

    Thanks for the quick fix.

    – Good news: I have got the email send and receive successfully after Part 2 with Thunderbird! Note: I set up Postfix with this subdomain: https://mail.mysite.com. I got score 8/10 at Mail-Tester.com due to have not set up SPF and DKIM in part 4 and 5 yet.

    – Bad news: after Part 3, I stuck at Step 6: Finish the Installation in Web Browser. Go to postfixadmin.example.com/setup.php
    I get this error at my website: https://mail.mysite.com – 403 Forbidden – nginx/1.14.0 (Ubuntu)

    I think I made a terrible mistake when I started Part 3 by setting up the subdomain: postfixadmin.example.com as the same with postfix: https://mail.mysite.com in Part2 for Postfix.

    To clarify my understanding as below:

    I need to host one server as server 1: 111.222.333.444 for Part 1+2 with Postfix and point the A records DNS to https://mail.mysite.com?
    And host another server as server 2: 555.666.777.888 for Part 3 to set up with PostfixAdmin and point the A records DNS to https://postfixadmin.mysite.com?

    What am I doing wrong? Can we install both Postfix and PostfixAdmin in one server with the subdomain https://mail.mysite.com only?

    Thanks again for your wonderful support and very quick reply.
    Regards,
    Quang

  • Hello Xiao Guoan. I have used your lessons more than once, and it always went well. This time I decided to deploy my own mail server and everything went fine until the end of 3rd lesson. It was necessary using the client to connect to the mailbox that was previously created through postfixadmin, but I did not succeed. I found an error in the logs which says that the passwords from dovecot and sql are different. I understand that dovecot encrypts passwords using ARGON2I, but sql doesn’t. Please tell how to fix it. I am enclosing an excerpt from the log file. I’m using raspberry pi 4, 4Gb Ram and Ubuntu server 20.04.

    Apr 26 20:16:04 mail dovecot: auth-worker(2431): Debug: sql([email protected],192.168.88.1,): query: SELECT username AS user,password FROM m>
    Apr 26 20:16:04 mail dovecot: auth-worker(2431): sql([email protected],192.168.88.1,): Password mismatch
    Apr 26 20:16:04 mail dovecot: auth-worker(2431): Debug: sql([email protected],192.168.88.1,): ARGON2I(xxxxxxxx) != '$1$18004242$5gcTGld6.Up>
    Apr 26 20:16:04 mail dovecot: auth-worker(2431): Debug: sql([email protected],192.168.88.1,): Finished passdb lookup
    Apr 26 20:16:04 mail dovecot: auth-worker(2431): Debug: conn unix:auth-worker (pid=2430,uid=113): auth-worker: Finished
    Apr 26 20:16:04 mail dovecot: auth: Debug: sql([email protected],192.168.88.1,): Finished passdb lookup
    Apr 26 20:16:04 mail dovecot: auth: Debug: auth([email protected],192.168.88.1,): Auth request finished
    Apr 26 20:16:06 mail dovecot: auth: Debug: client passdb out: FAIL#0112#[email protected] 
    • This line

      ARGON2I(xxxxxxxx) != '$1$18004242$5gcTGld6.Up>

      Indicates dovecot encrypts password with ARGONG2I, but the password stored in the database is encrypted with MD5. Please follow step 5 to configure PostfixAdmin to use Argon2 password scheme.

      Then delete the old email address in Postfixadmin and create a new one.

  • Hello Xiao Guoan. I have completed Step 5 The error was that postfixadmin is not using (config.local.php). I have made the changes you provided in (config.inc.php). I have deleted the mailbox through postfixadmin and created a new one. After this operation my mail client was able to connect, but I ran into a new problem. Given that lesson 3 was completed to the end, the password for logging into the admin panel of postfixadmin was created with the old encryption, and therefore I was no longer able to log into the admin panel of postfixadmin. It seems I will have to remove postfixadmin and reinstall it, but what will happen with the databases that postfixadmin has already created?

    • You don’t have to reinstall PostfixAdmin. Go to postfixadmin.example.com/setup.php to create a new superadmin account. Then delete the old superadmin account.

    • maximumwarp
      3 months ago

      Same system, same problem here!
      I think Postfixadmin doesn’t use config.local.php because config.inc.php try to include it from /etc/postfixadmin/ not from /usr/share/postfixadmin/

      • If PostfixAdmin doesn’t use it, you can create a symlink, so PostfixAdmin can find this file.

        sudo ln -s /usr/share/postfixadmin/config.local.php /etc/postfixadmin/config.local.php
  • Hi – great tutorials!

    I just tried to use

    sudo setfacl -R -m u:www-data:rwx /usr/share/postfixadmin/templates_c/

    and ubuntu 20.04 returns: sudo: setfacl: command not found

    Maybe you could add the hint to install the acl package

    sudo apt install acl

    BR

  • Hey Xiao

    I have finished part 3 tutorial and have come across an error when trying to send mail with thunderbird

    An error occurred while sending mail. The mail server responded:
    451 4.3.0 : Temporary lookup failure.
    Please check the message recipient “Destination email address again” and try again.

    I’ve checked the mail log and i believe it to be an error with
    warning: proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_maps.cf lookup error for “Redacted Email Address”

    • warning: proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_maps.cf lookup error for “Redacted Email Address”

      It could be there’s no such email address created in Postfixadmin.

    • It’s likely that you didn’t enter a correct password for the postfixadmin user in the .cf file under /etc/postfix/sql/ directory.

  • Ken Wright
    3 months ago

    Ni hao, Xiao!

    I’m still having trouble getting Thunderbird to log into the server. I’ve even gone so far as to wipe the server and start over, but I still can’t log in from Thunderbird. What do you need to help me diagnose the problem?

  • Ken Wright
    3 months ago

    Here’s the output from my mail log:

     May  4 16:58:30 grace dovecot: auth: Debug: client in: AUTH#0113#011PLAIN#011service=imap#011secured=tls#011session=NyHPb9WkdIvAqCwB#011lip=192.168.44.10#011rip=192.168.44.1#011lport=143#011rport=35700#011local_name=grace.koalatyworks.com#011ssl_cipher=TLS_AES_256_GCM_SHA384#011ssl_cipher_bits=256#011ssl_pfs=KxANY#011ssl_protocol=TLSv1.3#011resp=AHdpemFyZEBrb2FsYXR5d29ya3MuY29tAEIzY2NAYjAw (previous base64 data may contain sensitive data)
    May  4 16:58:38 grace dovecot: auth: Debug: sql([email protected],192.168.44.1,): Performing passdb lookup
    May  4 16:58:38 grace dovecot: auth-worker(47467): Debug: conn unix:auth-worker (pid=47450,uid=118): auth-worker: Handling PASSV request
    May  4 16:58:38 grace dovecot: auth-worker(47467): Debug: sql([email protected],192.168.44.1,): Performing passdb lookup
    May  4 16:58:38 grace dovecot: auth-worker(47467): Debug: sql([email protected],192.168.44.1,): query: SELECT username AS user,password FROM mailbox WHERE username = '[email protected]' AND active='1'
    May  4 16:58:38 grace dovecot: auth-worker(47467): sql([email protected],192.168.44.1,): Password mismatch
    May  4 16:58:38 grace dovecot: auth-worker(47467): Debug: sql([email protected],192.168.44.1,): ARGON2I([email protected]) != '$1$ae1f028e$sCMABJJJOjboh0QmoLEAs.', try DES-CRYPT scheme instead
    May  4 16:58:38 grace dovecot: auth-worker(47467): Debug: sql([email protected],192.168.44.1,): Finished passdb lookup
    May  4 16:58:38 grace dovecot: auth-worker(47467): Debug: conn unix:auth-worker (pid=47450,uid=118): auth-worker: Finished
    May  4 16:58:38 grace dovecot: auth: Debug: sql([email protected],192.168.44.1,): Finished passdb lookup
    May  4 16:58:38 grace dovecot: auth: Debug: auth([email protected],192.168.44.1,): Auth request finished
    May  4 16:58:40 grace dovecot: auth: Debug: client passdb out: FAIL#0113#[email protected]
    May  4 16:58:40 grace dovecot: imap-login: Disconnected (auth failed, 3 attempts in 26 secs): user=, method=PLAIN, rip=192.168.44.1, lip=192.168.44.10, TLS, session=
    May  4 16:59:06 grace postfix/anvil[47457]: statistics: max connection rate 4/60s for (smtp:192.168.44.1) at May  4 16:55:46
    May  4 16:59:06 grace postfix/anvil[47457]: statistics: max connection count 2 for (submission:192.168.44.1) at May  4 16:55:46
    May  4 16:59:06 grace postfix/anvil[47457]: statistics: max cache size 2 at May  4 16:55:46
    

    It looks to me like there’s a problem with the encryption of my password. Is there something I need to do with ARGON2I to make it work?

    • Maybe your config.loca.php file is missing the <?php opening tag.

      sudo nano /usr/share/postfixadmin/config.local.php

      Add the opening tag at the beginning of this file.

      <?php
      $CONF['encrypt'] = 'dovecot:ARGON2I';
      
      $CONF['dovecotpw'] = "/usr/bin/doveadm pw -r 5";
      if(@file_exists('/usr/bin/doveadm')) { // @ to silence openbase_dir stuff; see https://github.com/postfixadmin/postfixadmin/issues/171
          $CONF['dovecotpw'] = "/usr/bin/doveadm pw -r 5"; # debian
      }
      

      Then you should delete the old email address in PostfixAdmin and create a new one. If you can’t log into Postfixadmin, then go to the setup page https://postfixadmin.example.com/setup.php to create a new superadmin account.

  • Ron Jones
    2 months ago

    This is great stuff!
    The last mail server I built was on Ubuntu 16.04 from the instructions at exratione dotcom, and it’s been working great.

    But… recently, I decided it was time to move my mail server offsite to a VPS (my ISP won’t give me a PTR record for the static IP I’m paying for).

    Just finished with part 3, and Thunderbird logs in and sends mail just fine!

    I am following along, and everything seems to be working. I’ve only had a couple of challenges. But they were user error. Your instructions are very good. Log files are your friend (except with letsencrypt, because their logs aren’t that helpful lol).

    Just a suggestion: if you’ve got t-shirts or mugs, I’d be thrilled to buy them.

    Thanks,
    Ron

  • Christian
    2 months ago

    Generally, this is all working very well. I had a hiccup though with KMail.

    “Failed to transport message. Error during SSL handshake: error:1408F10B:SSL routines:ssl3_get_record:wrong version number.”

    I think this was because I tried to sign the email. What’s happening here?

    • The email client can’t establish TLS connection with Postfix or Dovecot. Try a different email client.

      • Christian
        2 months ago

        But it’s KMail. I really like KMail and so I’d prefer to keep using it. Is there a setting somewhere either in KMail or maybe in my server config files that can enable this connection?

        • Christian
          2 months ago

          Ahh never mind. My bad. KMail somehow detected the wrong smtp port plus left out the fact i needed username and password for smtp.
          I put the correct port and supplied my credentials and it works.
          thanks!

  • Harry DS Alsyundawy
    2 months ago

    Tq for good Tutorial,

    how setup Postfix and multiple SSL certificates with postfixadmin? i if have setup 10-200 domain in same machine

  • Mohamed Haboubi
    2 months ago

    Hello everyone,

    I’m trying to prepend the name of the user in the From section to be like this:
    – From: My Full Name

    Notice that the name is stored in the database the Mailbox table.

    Can someone help me to deal with this ?

  • It can be used with relay services?

    • Yes. Please read this article: How to Set up Postfix SMTP Relay on Ubuntu with Mailjet. As long as you use the Postfix SMTP server, you can follow this guide to set up SMTP relay.

      • ni hao ma, I read all articles not even one is good for what I need. If you can help me I will be grateful by running a Postifx in browser by using Ubuntu 20.4 along with Sendgrid. I searched all the internet for clues and all youtube and nothing found. Can you help?

    • You mean you need a web-based admin panel that allows you to configure SMTP relay (sendgrid) without having to edit configuration files from the command line?

      • ni hao ma xie xie for your reply. All I want is to send/receive/read emails on my Google Cloud platform. I read all articles related to SMTP Integrating with the SMTP API, Postfix etc. I don’t have a start point how to start and what to do to solve this.

      • I installed Postfix and configured it to relay on Sendgrid. I want to send emails/receive/read them in my web interface. How can I do this? What are the steps do I must follow to enable a web interface of Postfix?

  • Hello Xiao,
    one question, please:
    is it possible with this configuration(POstfix-Dovecot-Postfixadmin-Roundcube) to send an automatic message to a user(emailaccount) that they should change their password at a certain period? or for this is necessary to use a control panel like webmin
    Thanks!

    • You can use the Postfixadmin to send a broadcast message to all email accounts on the mail server. (Send email -> Broadcast message).

      Unfortunately, the postfixadmin-cli doesn’t support this feature, so you can’t use add this task in Cron, but have to manually broadcast the message in PostfixAdmin web interface.

  • Hi Xiao, I am new to Linux and tried to follow your tutorial to the letter…….. however, I must have made a typo or missed a step as i can’t get Thunderbird to connect to my server and get the following message and whe I check the status of dovecot.

    $ systemctl status dovecot
    ● dovecot.service - Dovecot IMAP/POP3 email server
         Loaded: loaded (/lib/systemd/system/dovecot.service; enabled; vendor preset: enabled)
         Active: active (running) since Fri 2020-06-26 01:55:50 AEST; 18h ago
           Docs: man:dovecot(1)
                 http://wiki2.dovecot.org/
       Main PID: 37925 (dovecot)
          Tasks: 6 (limit: 9379)
         Memory: 6.8M
         CGroup: /system.slice/dovecot.service
                 ├─37925 /usr/sbin/dovecot -F
                 ├─37948 dovecot/anvil
                 ├─37949 dovecot/log
                 ├─37950 dovecot/config
                 ├─38035 dovecot/stats
                 └─62680 dovecot/auth
    
    Jun 26 20:15:11 teseling.me dovecot[37949]: auth-worker(62694): Debug: Module loaded: /usr/lib/dovecot/modules/auth/lib20_auth_var_expand_crypt.so
    Jun 26 20:15:11 teseling.me dovecot[37949]: auth-worker(62694): Debug: Module loaded: /usr/lib/dovecot/modules/auth/libdriver_mysql.so
    Jun 26 20:15:11 teseling.me dovecot[37949]: auth-worker(62694): Error: mysql(localhost): Connect failed to database (postfixadmin): Access denied for user 'postfixadmin'@'localhost' (using password: YES) - waiting for 1 seconds before retry
    Jun 26 20:15:11 teseling.me dovecot[37949]: auth-worker(62694): Debug: conn unix:auth-worker (pid=62680,uid=131): Server accepted connection (fd=13)
    Jun 26 20:15:11 teseling.me dovecot[37949]: auth-worker(62694): Debug: conn unix:auth-worker (pid=62680,uid=131): Sending version handshake
    Jun 26 20:15:11 teseling.me dovecot[37949]: lmtp(62679): Disconnect from local: Client has quit the connection (state=READY)
    Jun 26 20:15:12 teseling.me dovecot[37949]: auth-worker(62694): Error: mysql(localhost): Connect failed to database (postfixadmin): Access denied for user 'postfixadmin'@'localhost' (using password: YES) - waiting for 5 seconds before retry
    Jun 26 20:15:17 teseling.me dovecot[37949]: auth-worker(62694): Error: mysql(localhost): Connect failed to database (postfixadmin): Access denied for user 'postfixadmin'@'localhost' (using password: YES) - waiting for 25 seconds before retry
    Jun 26 20:15:42 teseling.me dovecot[37949]: auth-worker(62694): Error: mysql(localhost): Connect failed to database (postfixadmin): Access denied for user 'postfixadmin'@'localhost' (using password: YES) - waiting for 125 seconds before retry
    Jun 26 20:16:11 teseling.me dovecot[37949]: auth-worker(62694): Debug: conn unix:auth-worker (pid=62680,uid=131): Disconnected: Connection closed (fd=-1)
    ~
    

    Your feedback would be appreciated.

    • The error indicates the postfixadmin user can’t log into MySQL/MariaDB database server.

      Check the .cf files under /etc/postfix/sql/ directory. The postfixadmin user password is included in those files. Make sure the password is correct. You can try to login as the postfixadmin user with this command.

      mysql -u postfixadmin -p

      You will need to enter the password for the postfixadmin user.

      You should also check the /etc/dovecot/dovecot-sql.conf.ext file, which incudes the postfixadmin user password. Make sure it’s entered correctly.

      Also note that the postfixadmin password should not contain the # character.

      • When inspecting /etc/dovecot/dovecot-sql.conf.ext I realised I haven’t replaced “password” in

        connect = host=localhost dbname=postfixadmin user=postfixadmin password=password

        with the password I have set in step 1 when installing postfixadmin.

        When restarting dovecot and postfix the error messages in /var/log/mail.log changed and are now: (I tried to remove a repetitive section of the error message lower down)

         Jun 26 21:33:12 teseling dovecot: master: Dovecot v2.3.7.2 (3c910f64b) starting up for imap, pop3, lmtp (core dumps disabled)
        Jun 26 21:34:02 teseling postfix/postfix-script[64468]: stopping the Postfix mail system
        Jun 26 21:34:02 teseling postfix/master[37681]: terminating on signal 15
        Jun 26 21:34:03 teseling postfix/postfix-script[64635]: warning: symlink leaves directory: /etc/postfix/./makedefs.out
        Jun 26 21:34:03 teseling postfix/postfix-script[64816]: starting the Postfix mail system
        Jun 26 21:34:03 teseling postfix/master[64818]: daemon started -- version 3.4.10, configuration /etc/postfix
        Jun 26 21:37:31 teseling dovecot: auth: Debug: Loading modules from directory: /usr/lib/dovecot/modules/auth
        Jun 26 21:37:31 teseling dovecot: auth: Debug: Module loaded: /usr/lib/dovecot/modules/auth/lib20_auth_var_expand_crypt.so
        Jun 26 21:37:31 teseling dovecot: auth: Debug: Module loaded: /usr/lib/dovecot/modules/auth/libdriver_mysql.so
        Jun 26 21:37:31 teseling dovecot: auth: Debug: Read auth token secret from /var/run/dovecot/auth-token-secret.dat
        Jun 26 21:37:31 teseling dovecot: auth: Debug: auth client connected (pid=65175)
        Jun 26 21:37:31 teseling dovecot: auth: Debug: client in: AUTH#0111#011PLAIN#011service=imap#011secured=tls#011session=iapvIvuo7rjL2RZ7#011lip=192.168.1.10#011rip=203.217.22.123#011lport=143#011rport=47342#011local_name=mail.teseling.me#011ssl_cipher=TLS_AES_256_GCM_SHA384#011ssl_cipher_bits=256#011ssl_pfs=KxANY#011ssl_protocol=TLSv1.3
        Jun 26 21:37:31 teseling dovecot: auth: Debug: client passdb out: CONT#0111#011
        Jun 26 21:37:31 teseling dovecot: auth: Debug: client in: CONT#0111#011AGNhcmVsQHRlc2VsaW5nLm1lAENGVF42eWhu (previous base64 data may contain sensitive data)
        Jun 26 21:37:31 teseling dovecot: auth: Debug: sql([email protected],203.217.22.123,): Performing passdb lookup
        Jun 26 21:37:31 teseling dovecot: auth-worker(65179): Debug: Loading modules from directory: /usr/lib/dovecot/modules/auth
        Jun 26 21:37:31 teseling dovecot: auth-worker(65179): Debug: Module loaded: /usr/lib/dovecot/modules/auth/lib20_auth_var_expand_crypt.so
        Jun 26 21:37:31 teseling dovecot: auth-worker(65179): Debug: Module loaded: /usr/lib/dovecot/modules/auth/libdriver_mysql.so
        Jun 26 21:37:31 teseling dovecot: auth-worker(65179): Debug: conn unix:auth-worker (pid=65177,uid=131): Server accepted connection (fd=14)
        Jun 26 21:37:31 teseling dovecot: auth-worker(65179): Debug: conn unix:auth-worker (pid=65177,uid=131): Sending version handshake
        Jun 26 21:37:31 teseling dovecot: auth-worker(65179): Debug: conn unix:auth-worker (pid=65177,uid=131): auth-worker: Handling PASSV request
        Jun 26 21:37:31 teseling dovecot: auth-worker(65179): Debug: sql([email protected],203.217.22.123,): Performing passdb lookup
        Jun 26 21:37:31 teseling dovecot: auth-worker(65179): Debug: sql([email protected],203.217.22.123,): query: SELECT username AS user,password FROM mailbox WHERE username = '[email protected]' AND active='1'
        Jun 26 21:37:31 teseling dovecot: auth-worker(65179): sql([email protected],203.217.22.123,): Password mismatch
        Jun 26 21:37:31 teseling dovecot: auth-worker(65179): Debug: sql([email protected],203.217.22.123,): ARGON2I(MYpassWORD) != '$argon2i$v=19$m=32768,t=5,p=1$umvtzWW2vJQPcvyZTOib8Q$xOWBjpqUd2oZjBPTc0OyxL7D7So/fJdcCF7gev4VPtQ'
        Jun 26 21:37:31 teseling dovecot: auth-worker(65179): Debug: sql([email protected],203.217.22.123,): Finished passdb lookup
        Jun 26 21:37:31 teseling dovecot: auth-worker(65179): Debug: conn unix:auth-worker (pid=65177,uid=131): auth-worker: Finished
        Jun 26 21:37:31 teseling dovecot: auth: Debug: sql([email protected],203.217.22.123,): Finished passdb lookup
        Jun 26 21:37:31 teseling dovecot: auth: Debug: auth([email protected],203.217.22.123,): Auth request finished
        Jun 26 21:37:33 teseling dovecot: auth: Debug: client passdb out: FAIL#0111#[email protected]
        
        .............Here I deleted what I thought was some repetitive errors...........
        
        Jun 26 21:37:45 teseling dovecot: auth: Debug: client passdb out: FAIL#0113#[email protected]
        Jun 26 21:38:37 teseling dovecot: imap-login: Disconnected (auth failed, 3 attempts in 66 secs): user=, method=PLAIN, rip=203.217.22.123, lip=192.168.1.10, TLS, session=
        Jun 26 21:38:43 teseling dovecot: auth-worker(65179): Debug: conn unix:auth-worker (pid=65177,uid=131): Disconnected: Connection closed (fd=-1)
        
    • Well, “password mismatch” indicates you entered a wrong password in the /etc/dovecot/dovecot-sql.conf.ext file.

      Is your mail server able to receive emails from other SMTP servers?

    • On second thought, it seems you are trying to login from a mail client via IMAP service, but the password for your email address wasn’t entered correctly.

      • Hi Xiao,
        Thanks for your feedback. Your “second thought” regarding the incorrect mail client password pointed me to the answer.
        I triple checked all my passwords and all were entered correctly.
        It turned out that when I removed the ^ from my email address password the mail client (Thunderbird) was able to connect to the IMAP and SMTP services and I can now send and receive emails.
        Now I will start on the other sections of your great tutorials.

  • Many thanks. Linuxbabe server guides are the gold standard for server setups.

  • The Americans
    2 weeks ago

    Turns out my 20.04 was missing dependencies for mysql and that was the big deal; to get mysql installed again, filling in the missing dependencies, then purging it all! Reinstalling it all, (because of an intentional bug I allege), then one thing after another until something couldn’t go wrong, then again another zillion of other things were fixed that were very wrong, then finally this wonderful updated single line “connect = host=localhost dbname=postfixadmin user=postfixadmin password=password!” Yes indeed, in which you did update within the last 48 hours or so huh! Well if I may just say so myself, updated so eloquently thank you very much! I did notice, so I am pleased to inform you and everyone else, everything email wise is working as of now again and I couldn’t be more ecstatic today because of all this terrible nonsense completely and totally radically “fixed!” Thank you so very much for your wonderful informative and invaluable information that you freely provided to everyone without any doubt, of course willing to learn and it’s so fun that you make it so much darn fun too!

    Have a Great Day,

    ZUH

  • Could you explain how to configure the display of quota usage?

  • For those with your “ubuntu 20.04LTS LEMP installation” already done do We need to “sudo apt install mysql-server” ? Is it not already installed ?

    Thank You so much.

    • As I said, you only need to run “sudo apt install mysql-server” if you have previously installed MySQL on your server and PostfixAdmin removed the “mysql-server” package from your server.

  • Hello Xiao
    This tutorial is amazing ! thanks for that.

    Unfortunately I can’t send email. but receiving it’s ok.

    /var/log/mail.log

    Aug  3 03:41:10 mail postfix/submission/smtpd[8107]: lost connection after AUTH from modemcable062.195-130-66.mc.videotron.ca[66.130.195.62]
    Aug  3 03:41:10 mail postfix/submission/smtpd[8107]: disconnect from modemcable062.195-130-66.mc.videotron.ca[66.130.195.62] ehlo=2 starttls=1 auth=0/2 commands=3/5
    Aug  3 03:41:26 mail dovecot: auth: Debug: auth client connected (pid=8174)
    Aug  3 03:41:26 mail dovecot: imap-login: Disconnected (no auth attempts in 0 secs): user=, rip=66.130.195.62, lip=167.114.159.154, TLS, session=
    Aug  3 03:42:04 mail postfix/postfix-script[8196]: stopping the Postfix mail system
    Aug  3 03:42:04 mail postfix/master[8015]: terminating on signal 15
    Aug  3 03:42:04 mail postfix/postfix-script[8324]: warning: symlink leaves directory: /etc/postfix/./makedefs.out
    Aug  3 03:42:04 mail postfix/postfix-script[8362]: starting the Postfix mail system
    Aug  3 03:42:04 mail postfix/master[8364]: daemon started -- version 3.4.14, configuration /etc/postfix
    Aug  3 03:42:04 mail dovecot: master: Warning: Killed with signal 15 (by pid=8370 uid=0 code=kill)
    Aug  3 03:42:06 mail dovecot: master: Dovecot v2.3.4.1 (f79e8e7e4) starting up for imap, pop3, lmtp (core dumps disabled)
    Aug  3 03:42:46 mail dovecot: auth: Debug: Loading modules from directory: /usr/lib/dovecot/modules/auth
    Aug  3 03:42:46 mail dovecot: auth: Debug: Module loaded: /usr/lib/dovecot/modules/auth/lib20_auth_var_expand_crypt.so
    Aug  3 03:42:46 mail dovecot: auth: Debug: Module loaded: /usr/lib/dovecot/modules/auth/libdriver_mysql.so
    Aug  3 03:42:46 mail dovecot: auth: Debug: Read auth token secret from /var/run/dovecot/auth-token-secret.dat
    Aug  3 03:42:46 mail dovecot: auth: Warning: sql: Ignoring changed user_query in /etc/dovecot/dovecot-sql.conf.ext, because userdb sql not used. (If this is intentional, set userdb_warning_disable=yes)
    Aug  3 03:42:46 mail dovecot: auth: Debug: auth client connected (pid=8392)
    Aug  3 03:42:46 mail dovecot: auth: Debug: client in: AUTH#0111#011PLAIN#011service=imap#011secured=tls#011session=ofngSPSrlpdCgsM+#011lip=167.114.159.154#011rip=66.130.195.62#011lport=143#011rport=38806#011local_name=mail.savoirs.ca#011$
    Aug  3 03:42:46 mail dovecot: auth: Debug: client passdb out: CONT#0111#011
    Aug  3 03:42:46 mail dovecot: auth: Debug: client in: CONT#0111#011AHNtZW5lQHNhdm9pcnMuY2EAMjQxMjI0YWJj (previous base64 data may contain sensitive data)
    Aug  3 03:42:46 mail dovecot: auth-worker(8396): Debug: Loading modules from directory: /usr/lib/dovecot/modules/auth
    Aug  3 03:42:46 mail dovecot: auth-worker(8396): Debug: Module loaded: /usr/lib/dovecot/modules/auth/lib20_auth_var_expand_crypt.so
    Aug  3 03:42:46 mail dovecot: auth-worker(8396): Debug: Module loaded: /usr/lib/dovecot/modules/auth/libdriver_mysql.so
    Aug  3 03:42:46 mail dovecot: auth-worker(8396): Debug: sql([email protected],66.130.195.62,): query: SELECT username AS user,password FROM mailbox WHERE username = '[email protected]' AND active='1'
    Aug  3 03:42:46 mail dovecot: auth: Debug: client passdb out: OK#0111#[email protected]#011
    Aug  3 03:42:46 mail dovecot: auth: Debug: master in: REQUEST#0113622961153#0118392#0111#0110b7d3b6d4fcd80d0f48a14acf1e0c370#011session_pid=8399#011request_auth_token
    Aug  3 03:42:46 mail dovecot: auth: Debug: master userdb out: USER#0113622961153#[email protected]#011uid=2000#011gid=2000#011home=/var/mail/vhosts/savoirs.ca/smene#011auth_token=22a636cb4b48deaa227a99f45ed3596a2004e2f5
    Aug  3 03:42:46 mail dovecot: imap-login: Login: user=, method=PLAIN, rip=66.130.195.62, lip=167.114.159.154, mpid=8399, TLS, session=
    Aug  3 03:43:01 mail dovecot: auth: Debug: auth client connected (pid=8402)
    Aug  3 03:43:01 mail dovecot: auth: Debug: client in: AUTH#0111#011PLAIN#011service=imap#011secured=tls#011session=sGfKSfSrpJdCgsM+#011lip=167.114.159.154#011rip=66.130.195.62#011lport=143#011rport=38820#011local_name=mail.savoirs.ca#011$
    Aug  3 03:43:01 mail dovecot: auth: Debug: client passdb out: CONT#0111#011
    Aug  3 03:43:01 mail dovecot: auth: Debug: client in: CONT#0111#011AHNtZW5lQHNhdm9pcnMuY2EAMjQxMjI0YWJj (previous base64 data may contain sensitive data)
    Aug  3 03:43:01 mail dovecot: auth-worker(8396): Debug: sql([email protected],66.130.195.62,): query: SELECT username AS user,password FROM mailbox WHERE username = '[email protected]' AND active='1'
    Aug  3 03:43:02 mail dovecot: auth: Debug: client passdb out: OK#0111#[email protected]#011
    Aug  3 03:43:02 mail dovecot: auth: Debug: master in: REQUEST#0113098542081#0118402#0111#011a3e86ed65212d6a319b267d539b7e4fb#011session_pid=8403#011request_auth_token
    Aug  3 03:43:02 mail dovecot: auth: Debug: master userdb out: USER#0113098542081#[email protected]#011uid=2000#011gid=2000#011home=/var/mail/vhosts/savoirs.ca/smene#011auth_token=94e2a6c5f8856d61260e52b2a0ce0ff6ea967d9a
    Aug  3 03:43:02 mail dovecot: imap-login: Login: user=, method=PLAIN, rip=66.130.195.62, lip=167.114.159.154, mpid=8403, TLS, session=
    Aug  3 03:43:03 mail postfix/submission/smtpd[8404]: connect from modemcable062.195-130-66.mc.videotron.ca[66.130.195.62]
    Aug  3 03:43:03 mail postfix/submission/smtpd[8404]: Anonymous TLS connection established from modemcable062.195-130-66.mc.videotron.ca[66.130.195.62]: TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-$
    Aug  3 03:43:03 mail dovecot: auth: Debug: auth client connected (pid=0)
    Aug  3 03:43:29 mail dovecot: auth: Debug: client in: AUTH#0111#011PLAIN#011service=smtp#011nologin#011lip=167.114.159.154#011rip=66.130.195.62#011secured#011resp=AHNtZW5lADI0MTIyNGFiYw== (previous base64 data may contain sensitive data)
    Aug  3 03:43:29 mail dovecot: auth-worker(8396): Debug: sql(smene,66.130.195.62): query: SELECT username AS user,password FROM mailbox WHERE username = 'smene' AND active='1'
    Aug  3 03:43:29 mail dovecot: auth-worker(8396): sql(smene,66.130.195.62): unknown user
    Aug  3 03:43:31 mail postfix/submission/smtpd[8404]: warning: modemcable062.195-130-66.mc.videotron.ca[66.130.195.62]: SASL PLAIN authentication failed:
    Aug  3 03:43:31 mail dovecot: auth: Debug: client passdb out: FAIL#0111#011user=smene
    Aug  3 03:43:31 mail dovecot: auth: Debug: client in: AUTH#0112#011LOGIN#011service=smtp#011nologin#011lip=167.114.159.154#011rip=66.130.195.62#011secured
    Aug  3 03:43:35 mail dovecot: auth: Debug: client passdb out: CONT#0112#011VXNlcm5hbWU6
    Aug  3 03:43:35 mail dovecot: auth: Debug: client in: CONT#0112#011c21lbmU= (previous base64 data may contain sensitive data)
    Aug  3 03:43:35 mail dovecAug  3 03:43:35 mail dovecot: auth: Debug: client passdb out: CONT#0112#011UGFzc3dvcmQ6
    Aug  3 03:43:35 mail dovecot: auth: Debug: client in: CONT#0112#011MjQxMjI0YWJj (previous base64 data may contain sensitive data)
    Aug  3 03:43:35 mail dovecot: auth-worker(8396): Debug: sql(smene,66.130.195.62): query: SELECT username AS user,password FROM mailbox WHERE username = 'smene' AND active='1'
    Aug  3 03:43:35 mail dovecot: auth-worker(8396): sql(smene,66.130.195.62): unknown user
    Aug  3 03:43:37 mail postfix/submission/smtpd[8404]: warning: modemcable062.195-130-66.mc.videotron.ca[66.130.195.62]: SASL LOGIN authentication failed: UGFzc3dvcmQ6
    Aug  3 03:43:37 mail dovecot: auth: Debug: client passdb out: FAIL#0112#011user=smene
    Aug  3 03:43:47 mail postfix/submission/smtpd[8404]: disconnect from modemcable062.195-130-66.mc.videotron.ca[66.130.195.62] ehlo=2 starttls=1 auth=0/2 quit=1 commands=4/6
    Aug  3 03:43:55 mail dovecot: imap([email protected]): Logged out in=107 out=604 deleted=0 expunged=0 trashed=0 hdr_count=0 hdr_bytes=0 body_count=0 body_bytes=0
    Aug  3 03:43:55 mail dovecot: imap([email protected]): Logged out in=572 out=10393 deleted=0 expunged=0 trashed=0 hdr_count=3 hdr_bytes=759 body_count=3 body_bytes=6976ot: auth: Debug: client passdb out: CONT#0112#011UGFzc3dvcmQ6
    Aug  3 03:43:35 mail dovecot: auth: Debug: client in: CONT#0112#011MjQxMjI0YWJj (previous base64 data may contain sensitive data)
    
    

    I don’t understand “unknown user” , everything looks fine in database.

    thanks for your help

    Best regards

    • Because you didn’t include the @domain.tld part in the username. The username should be your full email address.

      • Thank for your fast reply.

        Effectively the @domain.tdl was missing in username (incoming/outgoing) field in Thunderbird.

        Like this https://i.imgur.com/aemBKe3.png everything work fine. thank again.

        Maybe you should update your Thunderbird screenshot in this tutorial.

        And yes, this is the best tutorial on internet for mail server 🙂

        amazing work !

Leave a Comment

  • Comments with links are moderated by admin before published.
  • Your email address will not be published.
  • Use <pre> ... </pre> HTML tag to quote the output from your terminal/console.
  • Please use the community (https://community.linuxbabe.com) for questions unrelated to this article.
  • I don't have time to answer every question. Making a donation would incentivize me to spend more time answering questions.


The maximum upload file size: 2 MB.
You can upload: image.