Part 3: PostfixAdmin – Create Virtual Mailboxes on Ubuntu 18.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 account. This tutorial is going to show you how to create virtual mailboxes on Ubuntu 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 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.

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. This tutorial is for Ubuntu 18.04. If you are using Ubuntu 20.04, you should follow this PostfixAdmin guide instead.

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 😉

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 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

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-18.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. We need to give www-data user read, write and execute permissions on the Smarty template compile 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/

  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/;
   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.2-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include /etc/nginx/fastcgi_params;
   }
}

Note: This tutorial is written for Ubuntu 18.04. If you are using Ubuntu 16.04, change php7.2-fpm to php7.0-fpm.

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.2-fpm php7.2-imap php7.2-mbstring php7.2-mysql php7.2-json php7.2-curl php7.2-zip php7.2-xml php7.2-bz2 php7.2-intl php7.2-gmp

The above command is for Ubuntu 18.04. Ubuntu 16.04 doesn’t have php7.2 in its repository, run the following command to install php7.0 modules on Ubuntu 16.04.

sudo apt install php7.0-fpm php7.0-imap php7.0-mbstring php7.0-mysql php7.0-json php7.0-curl php7.0-zip php7.0-xml php7.0-bz2 php7.0-intl php7.0-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 18.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.

doveadm pw -l

Sample output:

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

To use stronger password schemes like Argon2, we need to upgrade Dovecot to v2.3. To check your Dovecot version, run

dovecot --version

Sample output:

2.2.33.2 (d6601f4ec)

We can install the latest version of Dovecot on Ubuntu 18.04 from the official upstream repository. (If you are using Ubuntu 19.10, you already have Dovecot 2.3.)

Create a repository file for Dovecot.

sudo nano /etc/apt/sources.list.d/dovecot.list

Add the following line in the file.

deb [arch=amd64] https://repo.dovecot.org/ce-2.3-latest/ubuntu/bionic bionic main

Save and close the file. Because this repository is using https, so we need to install the apt-transport-https package.

sudo apt install apt-transport-https

Then we need to import the Dovecot PGP key with the following two commands, so that packages downloaded from this repository can be verified.

curl https://repo.dovecot.org/DOVECOT-REPO-GPG | gpg --import
gpg --export ED409DA1 | sudo tee /etc/apt/trusted.gpg.d/dovecot.gpg

Now update repository and upgrade existing Dovecot packages.

sudo apt update
sudo apt upgrade

If you see a question like below in the upgrade process, it’s always a good idea to keep the local version and examine what needs to change later.

dovecot 2.3 argon password scheme

Once the upgrade is finished, check Dovecot version again.

dovecot --version

Output:

2.3.9.2 (cf2918cac)

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

Now we have Argon2. Edit the PostfixAdmin configuration file.

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

Find the following line.

$CONF['encrypt'] = 'md5crypt';

Change it to the following so that PostfixAdmin will use Dovecot’s ARGON2I password scheme.

$CONF['encrypt'] = 'dovecot:ARGON2I';

Then find the following line.

$CONF['dovecotpw'] = "/usr/bin/doveadm pw";

We need to add the number of rounds like 5 rounds. The minimum for ARGON2 is 3.

$CONF['dovecotpw'] = "/usr/bin/doveadm pw -r 5";

Save and close the file. 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.

postfix host multiple domains

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 /etc/postfixadmin/config.inc.php file to update the password hash. Replace changeme with your own password hash.

$CONF['setup_password'] = 'changeme';

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 away 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 so Dovecot can query user information from the 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

By default all lines are commented out. You can copy the following lines and paste them at the end of the file. 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

Save and close the file. 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.

Change User Password in PostfixAdmin

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

Troubleshooting

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.

It seems there’s a bug in PostfixAdmin 3.0.2, which always redirect users to the login page after clicking any link in the web interface.

To fix, edit the /usr/share/postfixadmin/common.php file and comment out the following lines. (Add // at the beginning of each line.) The latest version of PostfixAdmin doesn’t have these lines in common.php file.

if (defined('POSTFIXADMIN_LOGOUT')) {
        session_unset();
        session_destroy();
        session_start();
}

Save and close the file. You should be able to use PostfixAdmin.

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.

Next Step

I hope this tutorial helped you install and use PostfixAdmin on Ubuntu 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]

144 Responses to “Part 3: PostfixAdmin – Create Virtual Mailboxes on Ubuntu 18.04 Mail Server

  • Constantinos
    7 months ago

    Thank you very very much for doing all this work!

  • Hey, i got some problems, im goin step by step from your “how to”, and now i get one problem with Roundcube.
    I can send emails out, but i don’t recive any emails.
    They are not creating in /var/vmail/DOMAIN/USER/cur and anywhere…

    /var/log/mail.log looks like:

    Jan 15 18:21:20 HOST postfix/smtpd[28394]: connect from mail-ed1-f44.google.com[209.85.208.44]
    Jan 15 18:21:20 HOST postfix/smtpd[28394]: Anonymous TLS connection established from mail-ed1-f44.google.com[209.85.208.44]: TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)
    Jan 15 18:21:20 HOST postfix/smtpd[28394]: D2F7C2E3002: client=mail-ed1-f44.google.com[209.85.208.44]
    Jan 15 18:21:20 HOST postfix/cleanup[28399]: D2F7C2E3002: message-id=
    Jan 15 18:21:20 HOST postfix/qmgr[28381]: D2F7C2E3002: from=, size=3616, nrcpt=1 (queue active)
    Jan 15 18:21:20 HOST postfix/lmtp[28400]: D2F7C2E3002: to=, relay=none, delay=0.08, delays=0.06/0.02/0/0, dsn=4.4.1, status=deferred (connect to mail.xxx.com[private/dovecot-lmtp]: No such file or directory)
    Jan 15 18:21:20 HOST postfix/smtpd[28394]: disconnect from mail-ed1-f44.google.com[209.85.208.44] ehlo=2 starttls=1 mail=1 rcpt=1 data=1 quit=1 commands=7

    I see mails still coming to /var/mail/* .

    Any ideas what i can mess?

    • From the mail log, I can see that Postfix can’t connect to dovecot-lmtp. Make sure dovecot-lmtpd is installed.

      sudo apt install dovecot-lmtpd

      Edit the Dovecot main configuration file.

      sudo nano /etc/dovecot/dovecot.conf

      Add lmtp to the supported protocols.

      protocols = imap lmtp

      Save and close the file. Then edit the Dovecot 10-master.conf file.

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

      Change the lmtp service definition to the following.

      service lmtp {
       unix_listener /var/spool/postfix/private/dovecot-lmtp {
         group = postfix
         mode = 0600
         user = postfix
        }
      }

      Restart Postfix and Dovecot.

      sudo systemctl restart posfix dovecot

      PS: The above process has been explained in Part 2 of this tutorial series.

      • My fault – of course i miss this section.

        Thank you – greate job with that tutorial!

  • Ken Wright
    6 months ago

    I’ve followed your instructions, but for some reason when I try to run postfixadmin.mydomain.com I get a 404 status. I’ve set up the A record, but I’m still getting a 404.

    Obviously I’ve made a horrible mistake.

    Any suggestions?

    • Can you visit postfixadmin.yourdomain.com/setup.php?

      • Ken Wright
        6 months ago

        No. That gets me 404 as well.

        • Ken Wright
          6 months ago

          Well, I finally got postfixadmin.mydomain.com/setup.php to open, and after a few tries I finally got the admin account set up. I proceeded to login.php, but whenever I try to click a link it takes me back to the admin login screen. I’m thinking this isn’t the expected behavior. Any ideas?

    • This seems to be a bug in PostfixAdmin 3.0.2.

      To fix, edit the common.php file in the PostfixAdmin web root directory and comment out the following lines. (Add // at the beginning of each line.) The lastest version of PostfixAdmin doesn’t have these lines in common.php file.

      if (defined('POSTFIXADMIN_LOGOUT')) {
              session_unset();
              session_destroy();
              session_start();
           }
      

      Save and close the file and you should be able to use PostfixAdmin.

      • Ken Wright
        6 months ago

        It worked! Thanks, but now I seem to have a Thunderbird problem. It’s just not able to login to the server.

    • When you login from Thunderbird, you can check if there’s any error in the mail log (/var/log/mail.log).

      • Ken Wright
        6 months ago

        Here’s what I see most recently in the mail log:

        Feb 2 02:07:18 grace postgrey[1411]: Process Backgrounded
        Feb 2 02:07:18 grace postgrey[1411]: 2020/02/02-02:07:18 postgrey (type Net::Server::Multiplex) starting! pid(1411)
        Feb 2 02:07:18 grace postgrey[1411]: Resolved [localhost]:10023 to [127.0.0.1]:10023, IPv4
        Feb 2 02:07:18 grace postgrey[1411]: Binding to TCP port 10023 on host 127.0.0.1 with IPv4
        Feb 2 02:07:18 grace postgrey[1411]: Setting gid to “126 126”
        Feb 2 02:07:18 grace postgrey[1411]: Setting uid to “123”
        Feb 2 02:07:20 grace opendkim[1651]: OpenDKIM Filter v2.11.0 starting (args: -x /etc/opendkim.conf)

        I checked the log immediately after trying to log in from Thunderbird, which is still giving me the following error:

        Unable to log in at server. Probably wrong configuration, username or password.

        I hope this helps!

    • The above log messages is not related to login issue.

      You should add the following two lines in /etc/dovecot/conf.d/10-auth.conf file to debug login issues.

      auth_debug = yes
      auth_debug_passwords = yes

      Restart Dovecot and login again. Then you should be able to see dovecot errors in the /var/log/mail.log file.

      • Ken Wright
        6 months ago

        After I restarted Dovecot, I found this error in the log:

        Feb 2 06:40:53 grace dovecot: auth-worker(6367): Warning: mysql: Query failed, retrying: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‘=1’ at line 1

        Clearly, I’ve got a typo in an SQL table; the question is which one? I’ve looked at all seven in /etc/postfix/sql/ but they’re all good. When I look at /etc/dovecot/conf.d I don’t see anything that says sql or auth-worker, so I’m kind of stumped. Can you point me in the right direction?

    • Login is handled by Dovecot, not Postfix. You should look at your SQL syntax in the /etc/dovecot/dovecot-sql.conf.ext file. The content of this file should be:

      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
      
      • Ken Wright
        6 months ago

        This is turning into quite a bughunt! Now the log says it can’t find the “imap-sieve” plugin in /usr/share/dovecot/modules.

    • Run the following command to install sieve.

      sudo apt install dovecot-sieve dovecot-managesieved
      
      • Ken Wright
        6 months ago

        Sieve is already installed, but I made a typo in /etc/dovecot/conf.d/20-imap.conf; I typed “imap-sieve” instead of “imap_sieve” so it kinda choked.

        So I’m now able to log into the server, but I can’t send email. I get an error message saying the SMTP server is either unavailable or is refusing SMTP connections. I’ve checked the SMTP server settings and they match what you’ve got in the tutorial.

    • Have you enabled the submission service in Postfix? Is port 587 open on your server? You can list running services and the associated ports on your server with:

      sudo netstat -lnpt
      • Ken Wright
        6 months ago

        I’ve opened port 587. How do I enable the submission service?

    • If ported 587 is listed in the output of sudo netstat -lnpt, then you have enabled the submission service in Postfix. Steps of enabling submission service is described in part 2.

    • The sudo netstat -lnpt command list running services and the associated port on your server.

      Go to part 2 to enable submission service.

      • Ken Wright
        6 months ago

        Well, after a good night’s sleep, I went back through Part 2 and found a few mistakes I made. Typo’s and the like, but significant all the same. Anyway, I fixed the errors, restarted Postfix, and checked netstat again, and now port 587 is open.

        I tried sending an email from the new server, but this time I got an error message saying the connection timed out. I’m sure I’ve made another mistake, but I don’t know where!

    • Is the error message like this?

      connect to gmail-smtp-in.l.google.com[74.125.206.27]:25: Connection timed out

      This indicates that port 25 (outbound) is blocked by your ISP or hosting provider, so you can’t send email directly to the recipient. You need to set up SMTP relay to bypass port 25 blocking.

      • Ken Wright
        6 months ago

        No, it’s just a timeout message. Here it is:

        Sending of the message failed.
        The message could not be sent because the connection to Outgoing server (SMTP) grace.koalatyworks.com timed out. Try again.
    • Always check the error messages in the /var/log/mail.log file. If you don’t see any error message in the /var/log/mail.log file. This could mean that port 587 is still closed.

      Run the following command to open port 587 in firewall.

      sudo ufw allow 587/tcp
      • Ken Wright
        6 months ago

        Port 587’s open in the firewall. Tried sending another message, and the mail log shows the following:

        Feb  3 04:40:22 grace postfix/tlsmgr[2876]: fatal: do not use the same TLS cache file btree:/var/lib/postfix/smtpd_scache for smtpd and smtp
        Feb  3 04:40:23 grace postfix/master[30266]: warning: process /usr/lib/postfix/sbin/tlsmgr pid 2876 exit status 1
        Feb  3 04:40:23 grace postfix/master[30266]: warning: /usr/lib/postfix/sbin/tlsmgr: bad command startup -- throttling

        Which file should I check? /etc/postfix/main.cf or /etc/postfix/master.cf?

    • In the /etc/postfix/main.cf file, find the following two lines.

      smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
      
      smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

      This first parameter is the for the smtpd daemon, the second paramter is for the smtp client. Make sure they use different file names.

      • Ken Wright
        6 months ago

        Fixed that! Now the problem seems to be I’ve neglected to include mail.mydomain.com in my LetsEncrypt certificate. Is there a way to expand the certificate, or do I need to trash it and get a new one?

    • You can expand the certificate to include more domain name. First, edit the Nginx virtual host for grace.koalatyworks.com. Add a new hostname in the server_name directive.

      server_name grace.koalatyworks.com mail.koalatyworks.com;

      If there are two server_name directives, you need to change both of them.

      Reload nginx, then run the following command to obtain a certificate with two names on it.

      sudo certbot --nginx --agree-tos --redirect --hsts --staple-ocsp --email [email protected] -d grace.koalatyworks.com,mail.koalatyworks.com --cert-name grace.koalatyworks.com

      If the certificate is successfully obtained, restart Postfix and dovecot in order to pick up the new certificate.

      sudo systemctl restart postfix dovecot
      • Ken Wright
        6 months ago

        I tried this, and it wants to take koalatyworks.com, www.koalatyworks.com, postfixadmin.koalatyworks.com, and nextcloud.koalatyworks.com off the certificate. I really don’t want to lose those!

    • Then why not create a dedicated virtual host for mail.koalatyworks.com, and obtain a separate certificate?

    • By the way, your domain koalatyworks.com doesn’t have MX record. You should create MX record as described in part 1.

      • Ken Wright
        6 months ago

        Okay, I set the MX record and expanded my LetsEncrypt certificate to include grace.koalatyworks.com, but now I get this when I try to send an email:

        An error occurred while sending mail. The mail server responded:
        451 4.3.5 Server configuration error.

        I think I see the light at the end of the tunnel, but I hope it’s not an oncoming freight train!

    • Always check the /var/log/mail.log file.

      • Ken Wright
        6 months ago

        Here it is, but I don’t see any obvious error messages. If there’s an unobvious one, please show me what to look for.

        Feb  4 03:54:00 grace dovecot: imap([email protected]): Logged out in=106 out=577
        Feb  4 03:55:48 grace dovecot: auth: Debug: auth client connected (pid=2161)
        Feb  4 03:55:48 grace dovecot: auth: Debug: client in: AUTH#0111#011PLAIN#011service=imap#011secured#011session=4QniA7idxMvAqCwB#011lip=192.168.44.10#011rip=192.168.44.1#011lport=993#011rport=52164#011local_name=grace.koalatyworks.com
        Feb  4 03:55:48 grace dovecot: auth: Debug: client passdb out: CONT#0111
        Feb  4 03:55:48 grace dovecot: auth: Debug: client in: CONT#0111#011AHdpemFyZEBrb2FsYXR5d29ya3MuY29tAEIzY2NAYjAw (previous base64 data may contain sensitive data)
        Feb  4 03:55:48 grace dovecot: auth-worker(2163): Debug: Loading modules from directory: /usr/lib/dovecot/modules/auth
        Feb  4 03:55:48 grace dovecot: auth-worker(2163): Debug: Module loaded: /usr/lib/dovecot/modules/auth/lib20_auth_var_expand_crypt.so
        Feb  4 03:55:48 grace dovecot: auth-worker(2163): Debug: Module loaded: /usr/lib/dovecot/modules/auth/libdriver_mysql.so
        Feb  4 03:55:48 grace dovecot: auth-worker(2163): Debug: sql([email protected],192.168.44.1,): query: SELECT username AS user,password FROM mailbox WHERE username = '[email protected]' AND active='1'
        Feb  4 03:55:48 grace dovecot: auth: Debug: client passdb out: OK#0111#[email protected]
        Feb  4 03:55:48 grace dovecot: auth: Debug: master in: REQUEST#0113663724545#0112161#0111#01133f4421b5ab2716410d57f715e60ab09#011session_pid=2164#011request_auth_token
        Feb  4 03:55:48 grace dovecot: auth-worker(2163): Debug: sql([email protected],192.168.44.1,): SELECT maildir, 5000 AS uid, 5000 AS gid FROM mailbox WHERE username ='[email protected]' AND active = '1'
        Feb  4 03:55:48 grace dovecot: auth: Debug: master userdb out: USER#0113663724545#[email protected]#011maildir=koalatyworks.com/wizard/#011uid=5000#011gid=5000#011auth_token=7c1c12c49d02914d86d75de7f1151396174b8d4c
        Feb  4 03:55:48 grace dovecot: imap-login: Login: user=, method=PLAIN, rip=192.168.44.1, lip=192.168.44.10, mpid=2164, TLS, session=

        Does this help?

    • No. This is Dovecot log. You should look for Postfix log in the file. Try to send an email and look for any error message.

      • Ken Wright
        6 months ago

        I tried sending another email but nothing new showed up in the mail log. The only error message I see is the one I sent you earlier.

    • If you followed my tutorial series in the proper order, the situation would have been much better.

      I suggest reading the articles from part 1 to part 3 and compare the configurations.

      • Ken Wright
        6 months ago

        It’s working now!

        I rechecked /etc/postfix/master.cf and found I had put a period in one of the recipient restrictions instead of a comma. I fixed the typo, restarted Postfix, and now it’s working.

        Your tutorial series is DA BOMB! Thanks for the effort, and thanks for all the help you’ve given me the last few nights!

  • Ken Wright
    6 months ago

    Is the /usr/share/postfixadmin/templates_c/ directory supposed to be empty?

  • Hey great series so far! I’ve completed this section but I’m having trouble with a few of the address of that I’ve added. When I try to login via IMAP I get an unknown user error because it looks like its not passing the @domain. I can login via the postfixadmin user interface and change the password of the mail box. If I changed the devcot sql file to use local_part instead of username I could login. But I can’t send email from outside to the mail box so I’m sure I missed something…

    • Can you run the following command and show the output here?

      doveconf auth_username_format
      • Hey! I ran into some issues as well. Authentication with Outlook for Android does not work for me. By running this command I got the following warning:

        doveconf: Warning: please set ssl_dh= /etc/dovecot/dh.pem

        Do you have any idea how this could be the cause of my problem?

        • Edit SSL/TLS config file.

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

          Set DH parameters.

          ssl_dh=</etc/dovecot/dh.pem

          Save and close the file. Then generate the DH parameter.

          dd if=/var/lib/dovecot/ssl-parameters.dat bs=1 skip=88 | openssl dhparam -inform der | sudo tee /etc/dovecot/dh.pem

          Then restart Dovecot.

          sudo systemctl restart dovecot
  • Hi! I followed the steps but when I try to go to https://postfixadmin.mydomain.com/setup.php it gives me the following error: File not found.

    do you know how to fix this?

    Much appreciated! and awesome tutorials 🙂

    • Any idea how to fix the error “File not found” when going to postfixadmin.mydomain.com/setup.php?

    • Perhaps you can try removing the trailing slash of document root in the Apache configuration file.

      From this:

      /usr/share/postfixadmin/

      To this:

      /usr/share/postfixadmin
  • Feb  2 16:02:13 mail postfix/smtpd[1358]: connect from unknown[92.118.38.40]
    Feb  2 16:02:16 mail postfix/smtpd[1358]: disconnect from unknown[92.118.38.40] ehlo=1 auth=0/1 rset=1 quit=1 commands=3/4
    Feb  2 16:03:08 mail postfix/smtpd[1358]: warning: hostname ip-38-40.ZervDNS does not resolve to address 92.118.38.40: Name or service not known
    
    
    Feb  2 15:29:48 mail postfix/qmgr[10484]: 5CFD845862: from=, size=3665, nrcpt=1 (queue active)
    Feb  2 15:29:48 mail postfix/lmtp[1007]: 5CFD845862: to=, relay=none, delay=306683, delays=306683/0.02/0/0, dsn=4.4.1, status=deferred (connect to mail.insittes.com.br[private/dovecot-lmtp]: Connection refused)
    

    Help?

    • Have you followed part 2 to enable and configure the dovecot-lmtp service?

    • Yes, I followed part 1 and 2, all right, but you don’t receive email when I activate lmtp, these are the error logs.

    • Run the following command to check who is the owner.

      sudo ls -lh /var/spool/postfix/private/dovecot-lmtp

      Also check if Dovecot is running.

      systemctl status dovecot
    • [email protected]:~$ sudo ls -lh /var/spool/postfix/private/dovecot-lmtp
      srw——- 1 postfix postfix 0 Jan 29 19:29 /var/spool/postfix/private/dovecot-lmtp

    • The owner is correct. It should be postfix. Perhaps your Dovecot server isn’t running?

    • [email protected]:~$ dovecot -F
      doveconf: Fatal: Error in configuration file /etc/dovecot/conf.d/10-ssl.conf line 14: ssl_cert: Can't open file /etc/letsencrypt/live/mail.insittes.com.br/fullchain.pem: Permission denied
      

      I think this error should be the problem, how to fix the permission for the file?

    • I think that’s not the problem. If you run the command with sudo, the error would disappear.

      sudo dovecot -F

      Instead, you can check the dovecot log with:

      sudo journalctl -eu dovecot
    • [email protected]:~$ sudo dovecot -F
      doveconf: Fatal: Error in configuration file /etc/dovecot/conf.d/10-ssl.conf line 67: Unknown setting: protocolos
      [email protected]:~$ sudo journalctl -eu dovecot
      Feb 02 15:13:35 mail.insittes.com.br dovecot[898]: doveconf: Fatal: Error in configuration file /etc/dovecot/dovecot.conf: mailbox Rascunho: unknown special_use: \Rascu
      Feb 02 15:13:35 mail.insittes.com.br systemd[1]: dovecot.service: Main process exited, code=exited, status=89/n/a
      Feb 02 15:13:35 mail.insittes.com.br systemd[1]: dovecot.service: Failed with result 'exit-code'.
      Feb 02 15:18:26 mail.insittes.com.br systemd[1]: Started Dovecot IMAP/POP3 email server.
      Feb 02 15:18:26 mail.insittes.com.br dovecot[959]: doveconf: Fatal: Error in configuration file /etc/dovecot/dovecot.conf: mailbox Rascunho: unknown special_use: \Rascu
      Feb 02 15:18:26 mail.insittes.com.br systemd[1]: dovecot.service: Main process exited, code=exited, status=89/n/a
      Feb 02 15:18:26 mail.insittes.com.br systemd[1]: dovecot.service: Failed with result 'exit-code'.
      Feb 02 16:45:45 mail.insittes.com.br systemd[1]: Started Dovecot IMAP/POP3 email server.
      Feb 02 16:45:45 mail.insittes.com.br dovecot[1701]: doveconf: Fatal: Error in configuration file /etc/dovecot/dovecot.conf: mailbox Rascunho: unknown special_use: \Rasc
      Feb 02 16:45:45 mail.insittes.com.br systemd[1]: dovecot.service: Main process exited, code=exited, status=89/n/a
      Feb 02 16:45:45 mail.insittes.com.br systemd[1]: dovecot.service: Failed with result 'exit-code'.
      Feb 02 17:07:18 mail.insittes.com.br systemd[1]: Started Dovecot IMAP/POP3 email server.
      Feb 02 17:07:18 mail.insittes.com.br dovecot[1990]: doveconf: Fatal: Error in configuration file /etc/dovecot/conf.d/10-ssl.conf line 67: Unknown setting: protocolos
      Feb 02 17:07:18 mail.insittes.com.br systemd[1]: dovecot.service: Main process exited, code=exited, status=89/n/a
      Feb 02 17:07:18 mail.insittes.com.br systemd[1]: dovecot.service: Failed with result 'exit-code'.
      Feb 02 17:08:40 mail.insittes.com.br systemd[1]: Started Dovecot IMAP/POP3 email server.
      Feb 02 17:08:41 mail.insittes.com.br dovecot[2199]: doveconf: Fatal: Error in configuration file /etc/dovecot/conf.d/10-ssl.conf line 67: Unknown setting: protocolos
      
    • In the /etc/dovecot/conf.d/10-ssl.conf file, you have a typo. It should be “protocols”, instead of “protocolos”.

  • I do thank you for this great tutorial.
    I have a problem with the DNS A record in step 2 after creating the Apache virtual host and the setup file of postfixadmin does not open as a result. How do I have to create this A record in Linux?

    • You should create DNS record at your domain registrar’s website (such as NameCheap).

      Since you are asking this question, I think you don’t have a domain name. You should buy one in order to set up your own email server. And I think you didn’t read part 1 and part 2 of this tutorial series. You should start reading from part 1.

  • Hello,

    First of all, your tutorial is the best we can find on Internet. I searched a lot and I don’t know how I came to this one, but that’s the one I was looking for ! Keep up the good work !

    The thing is, I had issues and I solved a lot of them. I am a the end of the tutorial, and I have problems with user authentication and maybe creation. Postfix Admin works fine, no errors when I create users, but when I try to connect whit a client, I get thoses logs.

     pam_unix(dovecot:auth): check pass; user unknown
    Feb 10 21:31:34 mail.rt-lanparty.fr auth[12999]: pam_unix(dovecot:auth): authentication failure; logname= uid=0 euid=0 tty=dovecot ruser=webmaster rhost=37.165.138.104
    Feb 10 21:31:36 mail.rt-lanparty.fr dovecot[12928]: auth-worker(12999): pam(webmaster,37.165.138.104,): pam_authenticate() failed: Authentication failure (Password mismatch?) (given password: Dragon1807-)
    Feb 10 21:31:36 mail.rt-lanparty.fr dovecot[12928]: auth-worker(12999): Debug: sql(webmaster,37.165.138.104,): query: SELECT username AS user,password FROM mailbox WHERE username = 'webmaster' AND active='1'
    Feb 10 21:31:36 mail.rt-lanparty.fr dovecot[12928]: auth-worker(12999): sql(webmaster,37.165.138.104,): unknown user
    Feb 10 21:31:38 mail.rt-lanparty.fr dovecot[12928]: auth: Debug: client passdb out: FAIL        3        user=webmaster
    Feb 10 21:31:38 mail.rt-lanparty.fr dovecot[12928]: imap-login: Disconnected (auth failed, 3 attempts in 20 secs): user=, method=PLAIN, rip=37.165.138.104, lip=144.91.87.246, TLS, session=
    Feb 10 21:31:38 mail.rt-lanparty.fr dovecot[12928]: auth: Debug: auth client connected (pid=13020)
    Feb 10 21:31:38 mail.rt-lanparty.fr dovecot[12928]: auth: Debug: client in: AUTH        1        PLAIN        service=imap        secured=tls        session=2BVToD6eZuElpYpo        lip=144.91.87.246        rip=37.165.138.104        lport=
    Feb 10 21:31:38 mail.rt-lanparty.fr dovecot[12928]: auth: Debug: client passdb out: CONT        1
    Feb 10 21:31:38 mail.rt-lanparty.fr dovecot[12928]: auth: Debug: client in: CONT        1        AHdlYm1hc3RlckBydC1sYW5wYXJ0eS5mcgBEcmFnb24xODA3LQ== (previous base64 data may contain sensitive data)
    Feb 10 21:31:38 mail.rt-lanparty.fr dovecot[12928]: auth-worker(12999): Debug: pam([email protected],37.165.138.104,): lookup service=dovecot
    Feb 10 21:31:38 mail.rt-lanparty.fr dovecot[12928]: auth-worker(12999): Debug: pam([email protected],37.165.138.104,): #1/1 style=1 msg=Password:
    Feb 10 21:31:38 mail.rt-lanparty.fr auth[12999]: pam_unix(dovecot:auth): check pass; user unknown
    Feb 10 21:31:38 mail.rt-lanparty.fr auth[12999]: pam_unix(dovecot:auth): authentication failure; logname= uid=0 euid=0 tty=dovecot [email protected] rhost=37.165.138.104
    Feb 10 21:31:40 mail.rt-lanparty.fr dovecot[12928]: auth-worker(12999): pam([email protected],37.165.138.104,): pam_authenticate() failed: Authentication failure (Password mismatch?) (given password: Dragon1807-)
    Feb 10 21:31:40 mail.rt-lanparty.fr dovecot[12928]: auth-worker(12999): Debug: sql([email protected],37.165.138.104,): query: SELECT username AS user,password FROM mailbox WHERE username = '[email protected]
    Feb 10 21:31:40 mail.rt-lanparty.fr dovecot[12928]: auth: Debug: client passdb out: OK        1        [email protected]
    Feb 10 21:31:40 mail.rt-lanparty.fr dovecot[12928]: auth: Debug: master in: REQUEST        539230209        13020        1        c1388aff0741bba9988080839a747a4a        session_pid=13031        request_auth_token
    Feb 10 21:31:40 mail.rt-lanparty.fr dovecot[12928]: auth-worker(12999): Debug: passwd([email protected],37.165.138.104,): lookup
    Feb 10 21:31:40 mail.rt-lanparty.fr dovecot[12928]: auth-worker(12999): passwd([email protected],37.165.138.104,): unknown user
    Feb 10 21:31:40 mail.rt-lanparty.fr dovecot[12928]: auth-worker(12999): Debug: sql([email protected],37.165.138.104,): user_query = SELECT maildir, 2000 AS uid, 2000 AS gid FROM mailbox WHERE username = 'webmaster
    Feb 10 21:31:40 mail.rt-lanparty.fr dovecot[12928]: auth-worker(12999): Warning: sqlpool(mysql): Query failed, retrying: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right 
    Feb 10 21:31:40 mail.rt-lanparty.fr dovecot[12928]: auth-worker(12999): Error: sql([email protected],37.165.138.104,): User query failed: You have an error in your SQL syntax; check the manual that corresponds to 
    Feb 10 21:31:40 mail.rt-lanparty.fr dovecot[12928]: auth: Debug: master userdb out: FAIL        539230209
    Feb 10 21:31:40 mail.rt-lanparty.fr dovecot[12928]: imap: Error: Internal auth failure (auth connected 0 msecs ago, handshake 0 msecs ago, request took 0 msecs, client-pid=13020 client-id=1)
    Feb 10 21:31:40 mail.rt-lanparty.fr dovecot[12928]: imap-login: Internal login failure (pid=13020 id=1): user=, method=PLAIN, rip=37.165.138.104, lip=144.91.87.246, mpid=13031, TLS, session=
    
    

    Can you please give me a hint on this ?

    Cordialy.

    • You should look at your SQL syntax in the /etc/dovecot/dovecot-sql.conf.ext file. The content of this file should be:

      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
      
      
      • Thank you ! I just re-read my conf file and I wrote user_query = user_query… that is why it wasn’t working.

        May I ask another question ? Is it normal that the password is display in clear in the logs ?

    • The password is hashed with ARGON2I. It’s not a clear-text password.

      • Yes, It should be, I know.

        But see :

        auth-worker(2310): pam([email protected],144.91.87.246): pam_authenticate() failed: Authentication failure (Password mismatch?) (given password: password)
    • Disable login debugging in dovecot after you fixed the error.

  • Hello there,
    After completing “Step 10: Add Domain and Mailboxes in PostfixAdmin” I can send emails but cannot reveing emails. Here is the error:
    Final-Recipient: rfc822; [email protected]
    Original-Recipient: rfc822;[email protected]
    Action: failed
    Status: 5.1.1
    Diagnostic-Code: X-Postfix; unknown user: “USER1”

    Can anyone help with?

    • Check the mail log (/var/log/mail.log) to find out what’s wrong.

      • That is too technical to understand but looks like DEVOCOT is reacting:

        mail dovecot: imap-login: Disconnected (no auth attempts in 0 secs): user=, rip=XXX, lip=XXX, TLS handshaking: SSL_accept() failed: error:1417A0C1:SSL routines:tls_post_process_client_hello:no shared cipher, session=

        All emails sent to my server are not rejected and nor received. The server looks dumb.

    • If you can, please post all warnings and errors in the mail log file.

      • /var/log/mail.log is a huge file.

        the last error I can see is this:
        Feb 20 10:25:18 mail dovecot: auth-worker(6353): pam([email protected],2002:8a1:6df5:ca00:6464:72e6:b14c:c976,): pam_authenticate() failed: Authentication failure (Password mismatch?) (given password: PASSWORD)

    • Send an email to your email address, then open the mail log file and scroll down to the end of the file.

      • – When I send an email from my mail client to gmail, gmail receives it.
        – When I send an email from gmail to my server I can’t see at my mail client nor at /var/vmail/XXX/YYY/cur.
        – Now, if I drag and drop an email at mail client from one ICLOUD to INBOX of my server I can see it at /var/vmail/XXX/YYY/cur as well. If I delete it I can see a file at .Trash. as well.
        – here it goes the lines at /var/log/mail.log:

        Feb 20 11:10:13 mail postfix/smtpd[7185]: connect from unknown
        Feb 20 11:10:13 mail postfix/smtpd[7185]: NOQUEUE: reject: RCPT from unknown[156.96.116.52]: 454 4.7.1 : Relay access denied; from= to= proto=ESMTP helo=
        Feb 20 11:10:13 mail postfix/smtpd[7185]: disconnect from unknown[156.96.116.52] ehlo=1 mail=1 rcpt=0/1 rset=1 quit=1 commands=4/5
        Feb 20 11:11:11 mail dovecot: auth-worker(7155): Debug: conn unix:auth-worker (pid=7154,uid=112): Disconnected: Connection closed (fd=-1)
        Feb 20 11:11:23 mail postfix/smtpd[7185]: connect from mail-oln040092073024.outbound.protection.outlook.com[40.92.73.24]
        Feb 20 11:11:23 mail postfix/smtpd[7185]: Anonymous TLS connection established from mail-oln040092073024.outbound.protection.outlook.com[40.92.73.24]: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
        Feb 20 11:11:23 mail postfix/smtpd[7185]: 8B6293FB94: client=mail-oln040092073024.outbound.protection.outlook.com[40.92.73.24]
        Feb 20 11:11:23 mail postfix/cleanup[7190]: 8B6293FB94: message-id=
        Feb 20 11:11:23 mail postfix/qmgr[2553]: 8B6293FB94: from=, size=6339, nrcpt=1 (queue active)
        Feb 20 11:11:23 mail postfix/lmtp[7191]: 8B6293FB94: to=, relay=none, delay=0.08, delays=0.07/0.01/0/0, dsn=4.4.1, status=deferred (connect to DOMAIN[private/dovecot-lmtp]: No such file or directory)
        Feb 20 11:11:23 mail postfix/smtpd[7185]: disconnect from mail-oln040092073024.outbound.protection.outlook.com[40.92.73.24] ehlo=2 starttls=1 mail=1 rcpt=1 data=1 quit=1 commands=7
        Feb 20 11:13:37 mail dovecot: imap([email protected]): Logged out in=495 out=4253 deleted=0 expunged=0 trashed=0 hdr_count=0 hdr_bytes=0 body_count=0 body_bytes=0

    • This line:

      (connect to DOMAIN[private/dovecot-lmtp]: No such file or directory)

      indicates that Dovecot-LMTP is not working correctly. Please read the Dovecot LMTP instructions in part 2 carefully.

  • Thank You so much.
    For a reason I dont know I skipped the “Using Dovecot to Deliver Email to Message Store”.
    I am now on “7 Effective Tips for Blocking Email Spam with Postfix SMTP Server”.

  • – How di I redo completely this “sudo apt install postfixadmin”?
    – I did something wrong and now when I type this command it does not going from the beginning to all the steps.

  • How do I add a NOREPLY email address?

  • The nginx configuration for 18.04 requires that php-fpm be installed and as such, step 3 is missing the step:

    sudo apt install php-fpm

    • If you follow my LAMP stack or LEMP stack tutorial, you should have php-fpm installed already. I guess people would always ignore the prerequisites section when reading my articles 🙂

      • David Coles
        4 months ago

        Thank you Xiao, these are some of the best tutorials I’ve ever followed. My comment about php-fpm is that your LAMP tutorial just says it *may* be required, which suggests it is optional. Given that is a separate tutorial to this series, it isn’t obvious whether this tutorial series requires “Apache PHP module” or “PHP-FPM”. Having seen this comment, I will complete the last bit of the LAMP tutorial and switch to PHP-FPM. Thanks again.

  • I had a problem with a missing, respevtively faulty dovecot configuration in the /postfix/master.cf file. I always got following message:

    Mar  2 11:02:39 mail postfix/pipe[1158]: 89E24A24D0: to=, relay=dovecot, delay=596, delays=596/0/0/0.02, dsn=4.3.0, status=deferred (temporary failure. Command output: pipe: fatal: pipe_command: execvp /usr/libexec/dovecot/deliver: No such file or directory )
    

    I opened the configuration and added following:

    dovecot   unix  -       n       n       -       -       pipe
      flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -f ${sender} -d ${user}@${nexthop}
    

    thus making it possible to send a mail to another Mail account. Worth mentioning is, that I skipped all the encryption part and setting everything locally. It took few tries but all in all, it is working now.

  • Zsolt Nagy
    5 months ago

    Hello!
    I have followed the 1,st 2nd and 3rd parts of your tutorial. I set up virtual mailbox with Postgres instead of MySQL/MariaDB. I can send emails and it appears in e.g. gmail, but can’t receive any. Emails sent from postfixadmin are received.
    Gmail sent me the following:

    "The recipient server did not accept our requests to connect. Learn more at https://support.google.com/mail/answer/7720 [mail..com. : timed out]"

    There is no error in “mail.log” nor “mail.err”. Can’t find any error in journal neither.

    I had spam authentication issue, but commented out “auth-system.conf.ext”, because I use “auth-sql.conf.ext”:

     #!include auth-system.conf.ext
    !include auth-sql.conf.ext
    

    Furthermore, I also modified /etc/postfix/main.cf and now it looks like (tried it without the comment as well):

    virtual_transport = lmtp:unix:private/dovecot-lmtp
    #mailbox_transport = lmtp:unix:private/dovecot-lmtp
    smtputf8_enable = no
    

    Any suggestions?

    • The recipient server did not accept our requests to connect. Learn more at https://support.google.com/mail/answer/7720 [mail..com. : timed out]”

      This means that incoming connection to port 25 of your email server is blocked by a firewall. Make sure you have opened port 25 in iptables/ufw.

      There might also be another firewall sitting in front of your own email server. If that’s the case, you need to open port 25 in that firewall as well.

      You can use nmap command on another Linux machine to check if the inbound port 25 is open on your email server.

      sudo nmap mail.your-domain.com

      What do you mean by “spam authentication issue”?

      • Zsolt Nagy
        5 months ago

        Exactly, that was the problem. After I allowed port 25 it has started to work.
        “What do you mean by “spam authentication issue”?” just a typo, I wanted to write “pam”.
        Thank you very much 🙂

  • I’ve got this error:

    dovecot[6965]: auth: Fatal: sql: Unknown database driver ‘mysql’
    dovecot[6953]: master: Error: service(auth): command startup failed

    Can you help?

  • Hi Great tutorials, I have followed part 1 and 2, (I did install a later stable version of php 7.4) but struggling with the end of Step 2.
    http://postfixadmin.example.com/setup.php gets a file not found. It definitely hits my server, however I think it is still pointing to my other virtual host… mail.example.com.
    Following your previous advice, I have tried removed the trailing ‘/’, this had no luck. I also tried playing about with /public/ which is where the setup.php file resides.
    And I have tried removing the log file information.
    I am now fairly sure that it has something to do with Virtual host setup.
    Any help would be appreciated
    Next idea will be to try and move the folder to a sub-directory of my default option although I am sure that you suggested its location separate for good reason?
    N

    • UPDATE
      I solved above issue. I had entered https, which didn’t help – as it meant it would not resolve on my safari , on my iPad the page loaded with errors.
      I had to create a /templates_c folder/
      and redirect to ‘public’ although this was advised by the URL
      …..But hey – I have leant a lot about name-based virtual hosts.

      I then got stuck with a 451 error but I had accidentally skipped a lot of your material out… and hadn’t created the cf files.
      I didn’t reinstall the php stuff as I did that with the LAMP stack.
      Thanks again – onto the next part which coincidentally was something i was going to ask 🙂

  • Terence Love
    4 months ago

    Great tutorials. I’m learning a lot. Thank you.
    When I create Thunderbird user, it times out checking password (everything else good).
    Mail.log shows
    “Mar 29 13:16:30 mail dovecot: auth-worker(3486): Error: mysql(localhost): Connect failed to database (postfixadmin): Access denied for user ‘postfixadmin’@’localhost’ (using password: YES) – waiting for 25 seconds before retry”

    I’ve checked all code in Parts 1, 2 and 3 several times. Mysql opens with mysql -u postfixadmin -p and the copied password I’ve used in
    /etc/dbconfig-common/postfixadmin.conf
    /etc/postfixadmin/dbconfig.inc.php
    /etc/postfix/sql/mysql_virtual_domains_maps.cf
    /etc/postfix/sql/mysql_virtual_mailbox_maps.cf
    /etc/postfix/sql/mysql_virtual_alias_domain_mailbox_maps.cf
    /etc/postfix/sql/mysql_virtual_alias_maps.cf
    /etc/postfix/sql/mysql_virtual_alias_domain_maps.cf
    /etc/postfix/sql/mysql_virtual_alias_domain_catchall_maps.cf

    I welcome your advice on what I’ve missed.
    Best regards,
    Terry

    • Most likely your password was entered incorrectly in the .cf files.

      • Terence Love
        4 months ago

        Thank you Xiao Guoan,

        I have very carefully checked again each one of the .cf files and all contain the mysql database password correctly. I’m assuming this postfixadmin database password is the correct password for these cf files?

        One thought – Is it possible that having an # in the password is causing the problem?

        Another thought – I’ve just noticed 2 associated errors in the mail.err.1 log and these precede the failure to connect for postfixadmin :

        Mar 29 06:20:46 mail dovecot: auth-worker(24866): Error: sql(admin,X.X.X.X,): Password query failed: Not connected to database  [IP address and password removed by me]
        
        Mar 29 06:20:46 mail dovecot: auth: Error: auth worker: Aborted PASSV request for admin: Lookup timed out.

        Do these indicate anything that I need to change?

    • Terence Love
      4 months ago

      Hi Xiao Guo’an
      The error was a postfixadmin password that contained #.
      Perhaps good to suggest to readers to avoid symbols in passwords else identify which symbols cause problems?
      Many thanks for your wonderful tutorials. I’m looking forward to the next.
      Best wishes,
      Terence

    • Great. Thanks for the tip.

  • Hi, I’m getting this error

    … relay=none, delay=0.07, delays=0.02/0.01/0.04/0, dsn=5.4.6, status=bounced (mail for … loops back to myself)

    Thanks!

  • alias_database = hash:/etc/aliases
    alias_maps = hash:/etc/aliases
    append_dot_mydomain = no
    biff = no
    compatibility_level = 2
    inet_interfaces = all
    inet_protocols = all
    mailbox_size_limit = 0
    mydestination = mail.***.eu, localhost.***.eu, localhost
    myhostname = mail.***.eu
    mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
    myorigin = /etc/mailname
    readme_directory = no
    recipient_delimiter = +
    smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
    smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
    smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
    smtpd_tls_cert_file = /etc/ssl/certs/ssl-cert-snakeoil.pem
    smtpd_tls_key_file = /etc/ssl/private/ssl-cert-snakeoil.key
    smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
    smtpd_use_tls = yes
    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
    virtual_gid_maps = static:2000
    virtual_mailbox_base = /var/vmail
    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_minimum_uid = 2000
    virtual_transport = lmtp:unix:private/dovecot-lmtp
    virtual_uid_maps = static:2000

    Thank you for answering!

  • Hi,
    I’m following all tutorials to configure a mail server on my Raspberry Pi 4 with Ubuntu 18.04 LTS server.
    After the first two tutorials everything works like a charm: I installed Roundcube and I was able to send and receive emails with my Ubuntu account credentials. Now I followed this third tutorial for install Postfix Admin and manage virtual accounts.
    Postfix Admin installations was successful but now I can’t login to Roundcube webmail, I get “unable to connect to IMAP server”.
    I tried to configure Microsoft Outlook but it says it is unable to connect to IMAP server.

    I didn’t update Dovecot version to 2.3 because there isn’t arm64 build in repositories so I’m using version 2.2.33.2 and I chose SHA512-CRYPT password scheme.

    Can you help me, please?

    • *Edit: the correct error message in English is “Connection to storage server failed.”

    • You can upgrade to Ubuntu 19.10, or wait two weeks and upgrade to 20.04, so you will have Dovecot 2.3.

      • I’d prefer to stay with 18.04, it’s very complicated for me reconfigure the entire system (it hosts Nextcloud, WordPress, Plex and many other services…). I don’t think the problem is Dovecot version (and its password encryption scheme), can you suggest me sothing to do, please?

  • Thank you so much for such detailed and beginner friendly tutorial.

    I just have one issue, I am able to send the E-Mails but unable to receive any from External IDs (e.g. gmail). My mail.log also does not have any error.

    Relevant application ports for ufw app like Postfix, Postfix SMTPS, Postfix Submission, Dovecot IMAP, Dovecot POP3, Dovecot Secure IMAP, Dovecot Secure IMAP, Dovecot Secure POP3, 25/tcp
    are also open on the server, not sure what is wrong in my config.

    Would appreciate if you have any advice on how I can resolve this issue.

    postconf -n

     alias_database = hash:/etc/aliases
    alias_maps = hash:/etc/aliases
    append_dot_mydomain = no
    biff = no
    compatibility_level = 2
    inet_interfaces = all
    inet_protocols = all
    mailbox_command = procmail -a "$EXTENSION"
    mailbox_size_limit = 0
    mailbox_transport = lmtp:unix:private/dovecot-lmtp
    milter_default_action = accept
    milter_protocol = 6
    mydestination = localhost.$mydomain, localhost, $mydomain, mail.tealmail.com
    myhostname = mail.tealmail.com
    mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
    myorigin = /etc/mailname
    non_smtpd_milters = $smtpd_milters
    policyd-spf_time_limit = 3600
    readme_directory = no
    recipient_delimiter = +
    relayhost =
    smtp_tls_loglevel = 1
    smtp_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
    smtp_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
    smtp_tls_security_level = may
    smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
    smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
    smtpd_milters = local:opendkim/opendkim.sock
    smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination, check_policy_service unix:private/policyd-spf
    smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
    smtpd_tls_cert_file = /etc/letsencrypt/live/mail.tealmail.com/fullchain.pem
    smtpd_tls_key_file = /etc/letsencrypt/live/mail.tealmail.com/privkey.pem
    smtpd_tls_loglevel = 1
    smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
    smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
    smtpd_tls_security_level = may
    smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
    smtpd_use_tls = yes
    smtputf8_enable = no
    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
    virtual_gid_maps = static:2000
    virtual_mailbox_base = /var/vmail
    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_minimum_uid = 2000
    virtual_transport = lmtp:unix:private/dovecot-lmtp
    virtual_uid_maps = static:2000
    
    • You don’t have a valid MX record. You are using 648986190.pamx1.hotmail.com as your MX host. Instead, your MX record should point to mail.tealmail.com.

  • Hello, do you have any idea why catchall does’nt work? I’ve add alias @my.domain to [email protected] and add mysql_virtual_alias_domain_catchall_maps.cf like in your tutorial but somehow the catchall doesn’t work, I can send email to [email protected] but not caught by [email protected], this mail server of mine already runs fine for years but I just tried to use catchall right now.

  • Raffael Carvalho
    4 months ago

    Hello!
    (I write only in Portuguese, I’m sorry for the direct translation on google to English).
    Once again I thank you for your great tutorial. I need to implement an email sending limit per sasl user, that email would be daily. I tried to configure Postfwd and policyd-rate-threshold more without success. Do you have any tools to refer me? It would be very positive to include an item in your tutorial to create email sending limit policies per user, this will help prevent attacks on email accounts for sending spam.
    Thank you in advance.

  • Erik Olsen
    3 months ago

    I MADE IT THROUGH! 😀

    Seriously, thank you for these tutorials, I have been trying to get a Linux-based email server up for my business and they never seemed to work right. I followed your three guides plus the DKIM/SPF/DMARC add-ons and I am successfully able to send email to everywhere but Yahoo.com. I think their DNS updates are VERY slow so I am going to try it again later. GMAIL and other domains are fine; in fact, a few suppliers who I never bothered to change my email address with have been emailing my account since I finished the last settings you outlined.

  • Hi Xiao
    once again all appreciation for the best tutorial about a mail server.
    need some help again
    first off all, that issue with the redirection to login page everytime you click on a link in the web interface of postfix admin didn’t fix(at least for me) by commented those line in common.php. Checked on internet and found a fix from one guy(cristian boltz) that says it is a cookie issue and he sugested to create an empty file inside our postfixadmin web directory /usr/share/postfixadmin named favicon.ico and doing that fixed the issue

    then, when I reply from my yahoo account back to my new created email account i gert in yahoo a rejection return saying that: 550.1.1 recipient address rejected. User unknown in local recipient table

    thanks for some support

    • What is the output of this command:postconf mydestination and postconf myhostname

      • Here you are. Thank You!

        ~$ postconf mydestination
        mydestination = $myhostname, mail.10qconcept.com, localhost.com, , localhost

        ~$ postconf myhostname
        myhostname = 10qconcept.com

    • You should not use 10qconcept.com as the hostname. Run the following command to set mail.10qconcept.com as the hostname.

      sudo postconf -e "myhostname = mail.10qconcept.com"

      Then restart Postfix.

      sudo systemctl restart postfix
  • Jeremias Bohn
    2 months ago

    Hi,
    while most people have problems with receiving mails, my issue is the exact opposite: I can receive mails just fine, but I cannot send any mails.

    Content of /var/log/mail.log:

    13 17:31:52 h2835485 postfix/master[8060]: daemon started -- version 3.3.0, configuration /etc/postfix
    Jun 13 17:32:24 h2835485 postfix/smtpd[8066]: connect from [REDACTED]
    Jun 13 17:32:24 h2835485 postfix/smtpd[8066]: Anonymous TLS connection established from [REDACTED]: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
    Jun 13 17:32:24 h2835485 postfix/smtpd[8066]: NOQUEUE: reject: RCPT from [REDACTED]: 454 4.7.1 : Relay access denied; from= to= proto=ESMTP helo=
    Jun 13 17:32:24 h2835485 postfix/smtpd[8066]: disconnect from [REDACTED] ehlo=2 starttls=1 mail=1 rcpt=0/1 quit=1 commands=5/6
    

    Output of postconf -n
    alias_database = hash:/etc/aliases
    alias_maps = hash:/etc/aliases
    append_dot_mydomain = no
    biff = no
    compatibility_level = 2
    inet_interfaces = all
    inet_protocols = all
    mailbox_command = procmail -a “$EXTENSION”
    mailbox_size_limit = 0
    mailbox_transport = lmtp:unix:private/dovecot-lmtp
    mydestination = $myhostname, localhost.$mydomain, localhost, mail.jeremias-bohn.de
    myhostname = mail.jeremias-bohn.de
    myorigin = /etc/mailname
    readme_directory = no
    recipient_delimiter = +
    relayhost =
    smtp_tls_loglevel = 1
    smtp_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
    smtp_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
    smtp_tls_security_level = may
    smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
    smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
    smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
    smtpd_tls_cert_file = /etc/letsencrypt/live/mail.jeremias-bohn.de/fullchain.pem
    smtpd_tls_key_file = /etc/letsencrypt/live/mail.jeremias-bohn.de/privkey.pem
    smtpd_tls_loglevel = 1
    smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
    smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
    smtpd_tls_security_level = may
    smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
    smtputf8_enable = no
    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
    virtual_gid_maps = static:2000
    virtual_mailbox_base = /var/vmail
    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_minimum_uid = 2000
    virtual_transport = lmtp:unix:private/dovecot-lmtp
    virtual_uid_maps = static:2000

  • Jeremias Bohn
    2 months ago

    Thank you so much, Windows’s standard Mail app apparently doesn’t have a specific port field, you have to specify it with the URL! That’s why I forgot to do this!

    Also thanks for the great tutorial!

  • Olaawo Oluwapelumi
    1 month ago

    Thank you so much for the well detailed tutorial and the time spent to answer questions as regards this post.

    I was able to achieve the part every part covered so far except that mails sent from third party providers like GMAIL does get delivered to my inbox.

    E.G mail sent from ****@gmail.com doesnt get delivered to [email protected]

    I know this has to do with my hostname but i couldn’t notice where i messed things up.

    Below is the result of running : postconf mydestination

     mydestination = $myhostname, localhost.$mydomain, localhost 

    Also below are the last few lines of my /etc/postfix/main.cf

    smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
    myhostname = mail.my-domain.com
    alias_maps = hash:/etc/aliases
    alias_database = hash:/etc/aliases
    myorigin = /etc/mailname
    mydestination = $myhostname, localhost.$mydomain, localhost
    relayhost =
    mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
    mailbox_size_limit = 0
    recipient_delimiter = +
    inet_interfaces = all
    inet_protocols = all
    message_size_limit = 52428800
    mailbox_transport = lmtp:unix:private/dovecot-lmtp
    smtputf8_enable = no
    virtual_mailbox_base = /var/vmail
    virtual_minimum_uid = 2000
    virtual_uid_maps = static:2000
    smtp_header_checks = regexp:/etc/postfix/smtp_header_checks
    

    I hope you find time to look into my situation.

    Thanks.

    • Olaawo Oluwapelumi
      1 month ago

      Also running

       tail -f /var/log/mail.log 

      Then sending a mail to the server gives the following response

      Jun 23 10:00:31 mail postfix/smtpd[26872]: connect from mail-vs1-f52.google.com[209.85.217.52]
      Jun 23 10:00:31 mail postfix/smtpd[26872]: Anonymous TLS connection established from mail-vs1-f52.google.com[209.85.217.52]: TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)
      Jun 23 10:00:32 mail postfix/smtpd[26872]: NOQUEUE: reject: RCPT from mail-vs1-f52.google.com[209.85.217.52]: 454 4.7.1 : Relay access denied; from= to= proto=ESMTP helo=
      Jun 23 10:00:32 mail postfix/smtpd[26872]: disconnect from mail-vs1-f52.google.com[209.85.217.52] ehlo=2 starttls=1 mail=1 rcpt=0/1 data=0/1 quit=1 commands=5/7
      Jun 23 10:01:09 mail dovecot: auth-worker(26866): Debug: conn unix:auth-worker (pid=26865,uid=112): Disconnected: Connection closed (fd=-1)
      Jun 23 10:03:52 mail postfix/anvil[26874]: statistics: max connection rate 1/60s for (smtp:37.49.224.106) at Jun 23 10:00:20
      Jun 23 10:03:52 mail postfix/anvil[26874]: statistics: max connection count 1 for (smtp:37.49.224.106) at Jun 23 10:00:20
      Jun 23 10:03:52 mail postfix/anvil[26874]: statistics: max cache size 2 at Jun 23 10:00:31
      Jun 23 10:13:42 mail postfix/smtpd[26990]: warning: database /etc/aliases.db is older than source file /etc/aliases
      
      
    • You didn’t follow step 8.

  • Olaawo Oluwapelumi
    1 month ago

    I found that i left out the part that actually linked to the virtual maps

    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
    virtual_transport = lmtp:unix:private/dovecot-lmtp
    

    It works very well now.

    Thank you so much for providing this information completely for free and still being willing to attend to someone who missed his steps.

  • peacecop kalmer:
    4 weeks ago

    I did the setup before changing the hash type so I couldn’t log in afterwards and had to rewrite the hash in the config file and create a new admin user. After that, I could log in and change the password of the previous admin account.

  • The Americans
    4 weeks ago

    A problem was found with your Postfix virtual maps : The map source mysql:/etc/postfix/sql/mysql_virtual_alias_maps.cf cannot be used : Failed to query table : You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ‘from where = limit 1’ at line 1

    Any ideas?

    • The error message is self-explanatory. The SQL syntax is wrong. Open the /etc/postfix/sql/mysql_virtual_alias_maps.cf file and fix the syntax error.

      • The Americans
        4 weeks ago

        10.5.4-MariaDB-1:10.5.4+maria~focal mariadb.org binary distribution

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

    • You have apostrophes in the “query” line. They should be single quotes instead.

      PS: It seems you are using Ubuntu 20.04. You should follow this PostfixAdmin tutorial.

  • The Americans
    4 weeks ago

    Yes, yes we did follow 20.04; ended up here by a Google search accident see you over there @ 20.04 >>> Thanks ! ! !

  • Roy Esterhuizen
    3 weeks ago

    How do we go about enabling or getting the vacation/ out of office to work in postfixadmin?

  • RS BARI
    3 weeks ago

    I have trouble when step:

    Create superadmin account
    
    Setup password:
    Admin:
    Password:
    Password (again):
    

    Admin, Password and Password (again) leave empty?
    I can’t Add Admin on this step. Can you help me Xiao? Thanks

  • RS BARI
    2 weeks ago

    “To fix, edit the common.php file in the PostfixAdmin web root directory and comment out the following lines.”

    Where is location this file?

    • It’s /usr/share/postfixadmin/common.php 🙂

      • RS BARI
        2 weeks ago

        Ok, I found it. Thank you so much for attending to me 🙂

      • RS BARI
        2 weeks ago

        One question again please:

        Jul 17 12:04:57 vultr dovecot: config: Warning: NOTE: You can get a new clean config file with: doveconf -Pn > dovecot-new.conf
        Jul 17 12:04:57 vultr dovecot: config: Warning: Obsolete setting in /etc/dovecot/conf.d/10-ssl.conf:58: ssl_protocols has been replaced by ssl_min_protocol
        

        That is my mail.log, what is the meaning of this warning Xiao?

    • That’s because you upgraded Dovecot 2.2 to 2.3. ssl_protocols has been replaced by ssl_min_protocol in v2.3.

      Edit /etc/dovecot/conf.d/10-ssl.conf file, find the following line.

      ssl_protocols = !SSLv3 !TLSv1 !TLSv1.1

      Comment it out and add the following line.

      ssl_min_protocol = TLSv1.2

      Save and close the file. Then restart Dovecot.

      sudo systemctl restart dovecot

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.