Installing php-list and postfix for reliable e-mail campaigns

Installing php-list and postfix for reliable e-mail campaigns

Installing php-list

The purpose behind this turorial is to install php-list which is used for sending email campaigns, but insted of using php-list scripts to send emails to configure postfix to do the job. The reason i wanted to do this is so i could implement DKIM and DMARC (using opendkim and opendmarc) and therefore ensure that he campaign emails end would be blocked by strict rules or antispam filters.

I also wanted to manage a separate mail server using a subdomain of my main site. The reason for this is in case your ip's get blacklisted by the likes of google or hotmail, it will be easy to migrate the site (easy if you use services like digital ocean) or get another public ip. So the first step would be to install postfix and dovecot, php list uses postfix to send emails and it can also be configured to look into pop3 inboxes

From my setup i had a web site lets call it " for which whish to send campaigns, I create a separate VM where i have and configure to send campaign emails for To do this you wil need to add to the DNS records the correct dkim and dmarc enrties as well as modifying the existing SPF records.

Install postfix and dovecot

How To Configure a Mail Server Using Postfix, Dovecot and MySQL


In this tutorial, we are going to configure a mail server using Postfix, Dovecot, MySQL and SpamAssassin on Debian Jessie.

Following this tutorial you'll be able to add virtual domains, users, and aliases. Moreover, your virtual server will be secure from spam hub.


Before setting up your mail server, it's necessary your VPS has the following:

  • Domain is forwarding to your server ([setup domain][1])
  • MySQL installed and configured ([setup mysql][2])
  • User with root privileges ([setup new users][3]- omit step 5)
    *Configure and identify your FQDN ([setup FQDN][4])

Optional: SSL certificate ([setup free signed ssl certificate][5])

Optional ( Log in as root user )

Installing packages as the root user is useful because you have all privileges.

sudo -i

Introduce your user's password. Once it's successful, you will see that $ symbol changes to #.

Step 1: Install Packages

apt-get install postfix postfix-mysql dovecot-core dovecot-imapd dovecot-lmtpd dovecot-mysql

When Postfix configuration is prompted choose Internet Site:


Postfix configuration will ask about System mail name – you could use your FDQN or main domain.


Step 2: Create a MySQL Database, Virtual Domains, Users and Aliases

After the installation finishes, we are going to create a MySQL database to configure three different tables: one for domains, one for users and the last one for aliases.

We are going to name the database servermail, but you can use whatever name you want.

Create the servermail database:

mysqladmin -p create servermail

Log in as MySQL root user

mysql -u root -p

Enter your MySQL root's password; if it's successful you will see:

mysql >

First we need to create a new user, specific for mail authentication, and we are going to give SELECT permission.

mysql > GRANT SELECT ON servermail.* TO 'usermail'@'' IDENTIFIED BY 'mailpassword';

After that, we need to reload MySQL privileges to ensure it applies those permissions successfully:


Finally we need to use the database for creating tables and introduce our data:

mysql> USE servermail;

We are going to create a table for the specific domains recognized as authorized domains.

CREATE TABLE `virtual_domains` (
`name` VARCHAR(50) NOT NULL,

We are going to create a table to introduce the users. Here you will add the email address and passwords. It is necessary to associate each user with a domain.

CREATE TABLE `virtual_users` (
`domain_id` INT NOT NULL,
`password` VARCHAR(106) NOT NULL,
`email` VARCHAR(120) NOT NULL,
UNIQUE KEY `email` (`email`),
FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE

Finally we are going to create a virtual aliases table to specify all the emails that you are going to forward to the other email.

CREATE TABLE `virtual_aliases` (
`domain_id` INT NOT NULL,
`source` varchar(100) NOT NULL,
`destination` varchar(100) NOT NULL,
FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE

We have created the three tables successfully. Now we are going to introduce the data.

Virtual Domains

Here we are going to introduce your domains inside the virtual_domains table. You can add all the domains you want, but in this tutorial we are going to introduce just the primary domain ( and your FQDN (

INSERT INTO `servermail`.`virtual_domains`
(`id` ,`name`)
('1', ''),
('2', '');

Virtual Emails

We are going to introduce the email address and passwords associated for each domain. Make sure you change all the info with your specific information.

INSERT INTO `servermail`.`virtual_users`
(`id`, `domain_id`, `password` , `email`)
('1', '1', ENCRYPT('firstpassword', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))), ''),
('2', '1', ENCRYPT('secondpassword', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))), '');

Virtual Aliases

We are going to introduce the email address (source) that we are going to forward to the other email address (destination).

INSERT INTO `servermail`.`virtual_aliases`
(`id`, `domain_id`, `source`, `destination`)
('1', '1', '', '');

Exit MySQL

 mysql > exit

Step 3: Configure Postfix

We are going to configure Postfix to handle the SMTP connections and send the messages for each user introduced in the MySQL Database.

First we need to create a copy of the default file, in case you want to revert to the default configuration.

cp /etc/postfix/ /etc/postfix/

Open the file to modify it:

nano /etc/postfix/

First we need to comment the TLS Parameters and append other parameters. In this tutorial, we are using the Free SSL certificates and the paths that are suggested in the tutorial ([link][5]), but you could modify depending your personal configurations.

# TLS parameters
#smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
#smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
smtpd_tls_auth_only = yes

Then we are going to append the following parameters below the TLS settings that we have changed in the previous step:

smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_recipient_restrictions =

We need to comment the mydestination default settings and replace it with localhost. This change allows your VPS to use the virtual domains inside the MySQL table.

#mydestination =,,, localhost
mydestination = localhost

Verify that myhostname parameter is set with your FQDN.

myhostname =

Append the following line for local mail delivery to all virtual domains listed inside the MySQL table.

virtual_transport = lmtp:unix:private/dovecot-lmtp

Finally, we need to add these three parameters to tell Postfix to configure the virtual domains, users and aliases.

virtual_mailbox_domains = mysql:/etc/postfix/
virtual_mailbox_maps = mysql:/etc/postfix/
virtual_alias_maps = mysql:/etc/postfix/

Note: Compare these changes with this file to detect mistakes or errors:

<https:"" s="" x9fpm9v1dr86gkw="""">

We are going to create the final three files that we append in the file to tell Postfix how to connect with MySQL.

First we need to create the file. It's necessary to change the values depending your personal configuration.

nano /etc/postfix/

user = usermail
password = mailpassword
hosts =
dbname = servermail
query = SELECT 1 FROM virtual_domains WHERE name='%s'

Then we need to restart Postfix.

service postfix restart

We need to ensure that Postfix finds your domain, so we need to test it with the following command. If it is successful, it should returns 1:

postmap -q mysql:/etc/postfix/

Then we need to create the file.

nano /etc/postfix/

user = usermail
password = mailpassword
hosts =
dbname = servermail
query = SELECT 1 FROM virtual_users WHERE email='%s'

We need to restart Postfix again.

service postfix restart

At this moment we are going to ensure Postfix finds your first email address with the following command. It should return 1 if it's successful:

postmap -q mysql:/etc/postfix/

Finally, we are going to create the last file to configure the connection between Postfix and MySQL.

nano /etc/postfix/

user = usermail
password = mailpassword
hosts =
dbname = servermail
query = SELECT destination FROM virtual_aliases WHERE source='%s'

Restart Postfix

service postfix restart

We need to verify Postfix can find your aliases. Enter the following command and it should return the mail that's forwarded to the alias:

postmap -q mysql:/etc/postfix/

If you want to enable port 587 to connect securely with email clients, it is necessary to modify the /etc/postfix/ file

nano /etc/postfix/

We need to uncomment these lines and append other parameters:

submission inet n       -       -       -       -       smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject

In some cases, we need to restart Postfix to ensure port 587 is open.

service postfix restart

Note: You can use this tool to scan your domain ports and verify that port 25 and 587 are open (<http:"" supertool.aspx="">)

Step 4: Configure Dovecot

We are going to copy the 7 files we're going to modify, so that you could revert it to default if you needed to. Enter the following commands one by one:

cp /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf.orig
cp /etc/dovecot/conf.d/10-mail.conf /etc/dovecot/conf.d/10-mail.conf.orig
cp /etc/dovecot/conf.d/10-auth.conf /etc/dovecot/conf.d/10-auth.conf.orig
cp /etc/dovecot/dovecot-sql.conf.ext /etc/dovecot/dovecot-sql.conf.ext.orig
cp /etc/dovecot/conf.d/10-master.conf /etc/dovecot/conf.d/10-master.conf.orig
cp /etc/dovecot/conf.d/10-ssl.conf /etc/dovecot/conf.d/10-ssl.conf.orig

Edit configuration file from Dovecot.

nano /etc/dovecot/dovecot.conf

Verify this option is uncommented.

!include conf.d/*.conf

We are going to enable protocols (add pop3 if you want to) below the !include_try /usr/share/dovecot/protocols.d/*.protocol line.

!include_try /usr/share/dovecot/protocols.d/*.protocol
protocols = imap lmtp

Note: Compare these changes with this file to detect mistakes or errors:

<https:"" s="" wmbe3bwy0vcficj="" etc-dovecot-dovecot.conf.txt="">

Then we are going to edit the mail configuration file:

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

Find the mail_location line, uncomment it, and put the following parameter:

mail_location = maildir:/var/mail/vhosts/%d/%n

Find the mail_privileged_group line, uncomment it, and add the mail parameter like so:

mail_privileged_group = mail

Note: Compare these changes with this file to detect mistakes or errors:

<https:"" s="" hnfeieuy77m5b0a="" etc.dovecot.conf.d-10-mail.conf.txt="">

Verify permissions

Enter this command:

ls -ld /var/mail

Ensure permissions are like this:

drwxrwsr-x 3 root vmail 4096 Jan 24 21:23 /var/mail

We are going to create a folder for each domain that we register in the MySQL table:

mkdir -p /var/mail/vhosts/

Create a vmail user and group with an id of 5000

groupadd -g 5000 vmail
useradd -g vmail -u 5000 vmail -d /var/mail

We need to change the owner of the /var/mail folder to the vmail user.

chown -R vmail:vmail /var/mail

Then we need to edit the /etc/dovecot/conf.d/10-auth.conf file:

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

Uncomment plain text authentication and add this line:

disable_plaintext_auth = yes

Modify auth_mechanisms parameter:

auth_mechanisms = plain login

Comment this line:

#!include auth-system.conf.ext

Enable MySQL authorization by uncommenting this line:

!include auth-sql.conf.ext

Note: Compare these changes with this file to detect mistakes or errors:

<https:"" s="" 4h472nqrj700pqk="" etc.dovecot.conf.d.10-auth.conf.txt="">

We need to create the /etc/dovecot/dovecot-sql.conf.ext file with your information for authentication:

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

Enter the following code in the file:

passdb {
  driver = sql
  args = /etc/dovecot/dovecot-sql.conf.ext
userdb {
  driver = static
  args = uid=vmail gid=vmail home=/var/mail/vhosts/%d/%n

We need to modify the /etc/dovecot/dovecot-sql.conf.ext file with our custom MySQL information:

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

Uncomment the driver parameter and set mysql as parameter:

driver = mysql

Uncomment the connect line and introduce your MySQL specific information:

connect = host= dbname=servermail user=usermail password=mailpassword

Uncomment the default_pass_scheme line and change it to SHA-512.

default_pass_scheme = SHA512-CRYPT

Uncomment the password_query line and add this information:

password_query = SELECT email as user, password FROM virtual_users WHERE email='%u';

Note: Compare these changes with this file to detect mistakes or errors:

<https:"" s="" 48a5r0mtgdz25cz="" etc.dovecot.dovecot-sql.conf.ext.txt="">

Change the owner and the group of the dovecot folder to vmail user:

chown -R vmail:dovecot /etc/dovecot
chmod -R o-rwx /etc/dovecot

Open and modify the /etc/dovecot/conf.d/10-master.conf file (be careful because different parameters will be changed).

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

##Uncomment inet_listener_imap and modify to port 0
service imap-login {
  inet_listener imap {
    port = 0

#Create LMTP socket and this configurations
service lmtp {
   unix_listener /var/spool/postfix/private/dovecot-lmtp {
	   mode = 0600
	   user = postfix
	   group = postfix
  #inet_listener lmtp {
    # Avoid making LMTP visible for the entire internet
    #address =
    #port =

Modify unix_listener parameter to service_auth like this:

service auth {

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

  unix_listener auth-userdb {
  mode = 0600
  user = vmail
  #group =

  #unix_listener /var/spool/postfix/private/auth {
  # mode = 0666

  user = dovecot

Modify service auth-worker like this:

service auth-worker {
  # Auth worker process is run as root by default, so that it can access
  # /etc/shadow. If this isn't necessary, the user should be changed to
  # $default_internal_user.
  user = vmail

Note: Compare these changes with this file to detect mistakes or errors:

<https:"" s="" g0vnt233obh6v2h="" etc.dovecot.conf.d.10-master.conf.txt="">

Finally, we are going to modify the SSL configuration file from Dovecot (skip this step if you are going to use default configuration).

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

Change the ssl parameter to required:

ssl = required

And modify the path for ssl_cert and ssl_key:

ssl_cert = 

We need to open /etc/spamassassin/ to set up the anti-spam rules.

nano /etc/spamassassin/

SpamAssassin will score each mail and if it determines this email is greater than 5.0 on its spam check, then it automatically will be considered spam. You could use the following parameters to configure the anti-spam rules:

rewrite_header Subject ***** SPAM _SCORE_ *****
report_safe             0
required_score          5.0
use_bayes               1
use_bayes_rules         1
bayes_auto_learn        1
skip_rbl_checks         0
use_razor2              0
use_dcc                 0
use_pyzor               0

We need to change the Postfix /etc/postfix/ file to tell it that each email will be checked with SpamAssassin.

nano /etc/postfix/

Then we need to find the following line and add the spamassassin filter:

smtp      inet  n       -       -       -       -       smtpd
-o content_filter=spamassassin

Finally we need to append the following parameters:

spamassassin unix -     n       n       -       -       pipe
user=spamd argv=/usr/bin/spamc -f -e
/usr/sbin/sendmail -oi -f ${sender} ${recipient}

It is necessary to start SpamAssassin and restart Postfix to begin verifying spam from emails.

service spamassassin start
service postfix restart

Installing php-list

The next step is to install php-list which is quite straight forward.
Install dependencies

First make sure that all your system packages are up-to-date by running these following apt-get commands in the terminal.

sudo apt-get update
sudo apt-get upgrade

Install LAMP Stack

We will be installing Apache with apt-get, which is the default package manager for ubuntu:
apt-get install apache2

apt-get install apache2

You can verify that Apache is really running by opening your favorite web browser and entering the URL http://your-server’s-address, if it is installed, then you will see this:
Apache Default Page

apt-get install mysql-server mysql-client

Once complete, you can verify MySQL is installed by running the below command:
systemctl status mysql

systemctl status mysql

By default, MySQL is not hardened. You can secure MySQL using the mysql_secure_installation script. you should read and below each steps carefully which will set root password, remove anonymous users, disallow remote root login, and remove the test database and access to secure MySQL:


To log into MySQL, use the following command (note that it’s the same command you would use to log into a MySQL database):

mysql -u root -p

Installing PHP.

To install PHP and dependencies needed

apt-get -y install php5 php5-mysql libapache2-mod-php5

Your server should restart Apache automatically after the installation of both MySQL and PHP. If it doesn’t, execute this command:

service apache2 restart

service apache2 restart

To test PHP, create a test file named info.php with he content below. Save the file, then browse to it to see if PHP is working:

nano /var/www/html/info.php

nano /var/www/html/info.php

Try to access it at http://your_server_ip/info.php . If the PHP info page is rendered in your browser then everything looks good and you are ready to proceed further.
PHP version and Information

Download the latest stable version of PHPList, At the moment of writing this article it is version 3.0.12:

mkdir /var/www/html
mv phplist-3.2.5/public_html/lists/ /var/www/html/

We will need to change some folders permissions:

chown -R ww-data:www-data lists/

Step 4. Configuring MariaDB.

By default, MariaDB is not hardened. You can secure MariaDB using the mysql_secure_installation script. You should read and below each steps carefully which will set root password, remove anonymous users, disallow remote root login, and remove the test database and access to secure MariaDB.


Configure it like this:

Set root password? [Y/n] y
Remove anonymous users? [Y/n] y
Disallow root login remotely? [Y/n] y
Remove test database and access to it? [Y/n] y
Reload privilege tables now? [Y/n] y

Next we will need to log in to the Mysql or MariaDB console and create a database for the PHPList. Run the following command:

mysql -u root -p

This will prompt you for a password, so enter your MariaDB root password and hit Enter. Once you are logged in to your database server you need to create a database for PHPList installation:

MariaDB > create database phplist;
MariaDB > grant all privileges on phplist.* to phplistuser@localhost identified by 'your_password';
MariaDB > flush privileges;
MariaDB > exit

Now edit PHPList configuration file config/config.php and update following values. Change value of TEST variable to 0 to disable test mode (0=disable test mode, 1=enable test mode):

nano lists/config/config.php

$database_host = "localhost";
$database_name = "phplist";
$database_user = "phplistuser";
$database_password = 'your_password';

define ("TEST",0);

Now, we can restart Apache and MariaDB so that the changes take place:

systemctl restart apache2.service
systemctl restart mariadb.service

Step 6. Accessing PHPList.

PHPList will be available on HTTP port 80 by default. Open your favorite browser and navigate to or http://server-ip/lists/admin and complete the required the steps to finish the installation. If you are using a firewall, please open port 80 to enable access to the control panel.

phpList dashboard