A Linux mail server consists of software packages that can send and receive mail using the SMTP protocol and retreive mail using the standard protocols POP3 and / or IMAP. Since we are about to setup your new Linux mail server, it is important to understand the differences between the various protocols and their purposes. SMTP is typically used to deliver mail from a client to a server or pass messages from one server to another. POP3 (Post-Office Protocol) is an uni-directional protocol, which retrieves mail from the mail server and delivers it to a mail client like Mozilla’s Thunderbird. POP3 differs from IMAP with one significant respect: IMAP synchronizes messages between different d whereas POP3 simply downloads copies of messages.
The default configuration for the mail server software we are going to use to build our server is setup for a single domain. However, it is more useful to create a server that can not only accomodate multiple email addresses, but also multiple domains. The most convenient way to manage these multple domains and email addresses is to use a MySQL database as a backend.
Preparing Your Linux Mail Server
First, let’s prepare the system by installing the required packages:
apt-get install vim postfix postfix-mysql postfix-doc mysql-client mysql-server courier-authdaemon courier-authlib-mysql courier-pop courier-pop-ssl courier-imap courier-imap-ssl libsasl2-2 libsasl2-modules libsasl2-modules-sql sasl2-bin libpam-mysql openssl phpmyadmin apache2 libapache2-mod-php5 php5 php5-mysql libpam-smbpass php5-imap
During installation, you’ll be asked the following questions:
Question 1: What type of server site do you want? Select Internet Site
Question 2: Enter the FQDN (Fully Qualified Domain Name)
This is the full domain name that you will put into in the MX Records. Make sure this has already been entered into the DNS at your registrar / name servers. The example below shows mail.domain.com, but you will want to change it to your legitimate mail server address (or backup MX record).
Question 3: Enter the administrative “root” user password.
Question 4: Create directories for web-based administration?
Question 5: Is not really a question.
It just tells you that you are going to need an SSL certificate. Just click OK.
Question 6: For the Samba server, leave the workgroup name “WORKGROUP”
Question 7: Next, phpMyAdmin will ask you to choose the web server it will use. Select Apache.
Question 8: Configure the database for phpMyAdmin with dbconfig-common? Select Yes.
Question 9: Enter the password for the database administrative user.
Question 10: Next, it will ask you for a password to register with the MySQL server. Enter in the root password you put in for question 3 above.
The installation of the software packages will continue and return you to the prompt. Next, we’ll need to configure the database system so we can support multiple domains and multiple users. The easiest way to do this is to install postfixadmin, and let postfixadmin create the database tables we will use to manage the system.
Setting Up the Database
Making Sure the MySQL Database Server is “listening”
Edit the /etc/mysql/my.cnf file to ensure that bind-address on line 47 is configured to be 127.0.0.1. If it was not, change the directive to the following:
bind-address = 127.0.0.1
and then restart the MySQL service with this command:
Setup a User for the Database
Log into the MySQL client:
msyql -uroot -p
Enter the password you created for root above. (See Question 3 above!)
CREATE DATABASE postfix; GRANT ALL ON postfix.* to 'postfixadmin'@'localhost' IDENTIFIED BY 'changethispassword';
Change to the /var/www/ directory (Apache’s document root)
Download the current version of postfixadmin:
wget -O postfixadmin.tar.gz http://sourceforge.net/projects/postfixadmin/files/latest/download
Untar the package:
tar -zxvf postfixadmin.tar.gz
Postfixadmin will likely untar into a directory like postfixadmin-2.3.5, which is not very convenient for us. So, let’s move it to a more memorable, easier directory:
mv -v postfixadmin-2.3.5/ postfixadmin/
Edit config.inc.php, and change line 27 to set $CONF['configured'] to true:
//$CONF['configured'] = false; $CONF['configured'] = true;
Now, configure the database permissions on line 52-54 (approximately). Change the username to postfixadmin and the password to the password you configured above.
Once you have completed the configuration of PostfixAdmin, you can now navigate to the setup script in the browser by going to the IP address of the server /postfix/admin.php.
The script will check your setup and alert you to any errors. If you have followed this tutorial closely (and correctly) there should be no errors. If there are, however, double check the process, and correct any errors that are being shown.
Once you correct any errors, it will ask you to enter in a setup password. Enter in the password, and click the Generate Password Hash button. Once you do so, it will give you a line configuration that we will enter into config.inc.php.
Copy and paste that configuration line to the end of the config.inc.php, and then refresh the page.
Once the page is refreshed, enter in the setup password, and create a master email account that will serve as the superadmin account. Once you have completed this process, double check to make sure that the setup script has notified you of two events:
Everything seems fine... attempting to create/update database structure Database is up to date
Once you see these messages, the database and table structures are created, and we are ready to move on to the next part of the process.
Change directory to /var/www/
Download the current version of phpMyAdmin:
wget -O phpmyadmin.tar.gz http://downloads.sourceforge.net/project/phpmyadmin/phpMyAdmin/3.5.2/phpMyAdmin-3.5.2-english.tar.gz?r=http%3A%2F%2Fwww.phpmyadmin.net%2Fhome_page%2Fdownloads.php&ts=1342151305&use_mirror=iweb
tar -zxvf phpmyadmin.tar.gz
Move the directory to something more usable:
mv -v phpMyAdmin-3.5.2-english/ phpMyAdmin/
Navigate to http://192.168.1.100/phpMyAdmin/ and log in using postfixadmin and the password you set for the postfixadmin user to double check to make sure that user permissions are correct. Upon logging in, you should see the postfix table listed on the left hand side, and then the following list of tables will be shown:
Configuring Postfix to Use MySQL
There are six files that we are going to configure to work with our configuration as we have set it up thus far, which are all located in /etc/postfix/:
This file tells postfix what domains the mail server will be receiving mail for. Here are the contents:
user = postfixadmin password = thepostfixadminpassword dbname = postfix query = SELECT domain AS virtual FROM domain WHERE domain='%s' hosts = 127.0.0.1
This table sets up email forwarding and aliases. Its content should be:
user = postfixadmin password = thepostfixadminpassword dbname = postfix query = SELECT goto FROM alias WHERE address='%s' hosts = 127.0.0.1
This file tells Postfix where in your local mail server’s file system the mail will be kept. The SQL statement parses the email address and turns it into a relative path from the mail root. It’s file contents are:
user = postfixadmin password = thepostfixadminpassword dbname = postfix query = SELECT CONCAT(SUBSTRING_INDEX(username,'@',-1),'/',SUBSTRING_INDEX(username,'@',1),'/') FROM mailbox WHERE username='%s' hosts = 127.0.0.1
This tells Postfix how to find and indentify aliases. It’s contents should consist of:
user = postfixadmin password = thepostfixadminpassword dbname = postfix query = SELECT username FROM mailbox WHERE username='%s' hosts = 127.0.0.1
Postfix needs to be told how to transport emails from the point of receipt to teh final destination. For our purposes (and mostly because we are configuring this server with PostfixAdmin), we are going to use “virtual” as the transport because this server receives mail for virtual hosts. The file contents and configuration for this consist of:
user = postfixadmin password = thepostfixadminpassword dbname = postfix query = SELECT transport FROM domain WHERE domain='%s' hosts = 127.0.0.1
This last configuration file tells Postfix how to limit email accounts based on a quota. Its configuration file should be:
user = postfixadmin password = thepostfixadminpassword dbname = postfix query = SELECT current FROM quota WHERE username='%s' hosts = 127.0.0.1
Now, we have to change the ownership and group of the files to make Postfix happy:
chmod o= /etc/postfix/mysql-virtual_*.cf chgrp postfix /etc/postfix/mysql-virtual_*.cf
Now, we have to create a user and group that will own and operate the virtual mail stores (along with the home directory where all the mail will be stored)
groupadd -g 5000 vmail useradd -g vmail -u 5000 vmail -d /home/vmail -m
Next, use the commands below to configure Postfix to use the MySQL tables and configuration files we have set up to this point. Be sure to change changeme.example.com to your FQDN or you’ll break Postfix!
postconf -e 'myhostname = changeme.example.com' postconf -e 'mydestination = changeme.example.com, localhost, localhost.localdomain' postconf -e 'mynetworks = 127.0.0.0/8' postconf -e 'virtual_alias_domains =' postconf -e 'virtual_alias_maps = proxy:mysql:/etc/postfix/mysql-virtual_forwardings.cf, mysql:/etc/postfix/mysql-virtual_email2email.cf' postconf -e 'virtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql-virtual_domains.cf' postconf -e 'virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql-virtual_mailboxes.cf' postconf -e 'virtual_mailbox_base = /home/vmail' postconf -e 'virtual_uid_maps = static:5000' postconf -e 'virtual_gid_maps = static:5000' postconf -e 'smtpd_sasl_auth_enable = yes' postconf -e 'broken_sasl_auth_clients = yes' postconf -e 'smtpd_sasl_authenticated_header = yes' postconf -e 'smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination' postconf -e 'smtpd_use_tls = yes' postconf -e 'smtpd_tls_cert_file = /etc/postfix/smtpd.cert' postconf -e 'smtpd_tls_key_file = /etc/postfix/smtpd.key' postconf -e 'transport_maps = proxy:mysql:/etc/postfix/mysql-virtual_transports.cf' postconf -e 'virtual_create_maildirsize = yes' postconf -e 'virtual_maildir_extended = yes' postconf -e 'virtual_mailbox_limit_maps = proxy:mysql:/etc/postfix/mysql-virtual_mailbox_limit_maps.cf' postconf -e 'virtual_mailbox_limit_override = yes' postconf -e 'virtual_maildir_limit_message = "The user you are trying to reach is over quota."' postconf -e 'virtual_overquota_bounce = yes' postconf -e 'proxy_read_maps = $local_recipient_maps $mydestination $virtual_alias_maps $virtual_alias_domains $virtual_mailbox_maps $virtual_mailbox_domains $relay_recipient_maps $relay_domains $canonical_maps $sender_canonical_maps $recipient_canonical_maps $relocated_maps $transport_maps $mynetworks $virtual_mailbox_limit_maps'
Create SSL Certificates for Secure Connections
Using the commands below, create a certificate for your server to use to send and receive secure, encrypted mail. (You may, alternatively, purchase one from a certificate authority).
cd /etc/postfix openssl req -new -outform PEM -out smtpd.cert -newkey rsa:2048 -nodes -keyout smtpd.key -keyform PEM -days 365 -x509
Openssl will now generate SSL Certificates for you, but will need to encode some information about you and your organization to do so. (If you are a personal user, don’t worry… you can fill in anything you want here. Here are some suggested values:
Country Name (2 letter code) [AU]:US State or Province Name (full name) [Some-State]:GA Locality Name (eg, city) :Atlanta Organization Name (eg, company) [Internet Widgits Pty Ltd]:High Society for Schrödinger's Cat Lovers Organizational Unit Name (eg, section) :Cardboard Box Division Common Name (eg, YOUR name) :yourfqdn.yourdomain.com Email Address :email@example.com
As you can see, the only value here that really matters is the common name which must match the fully qualified domain name that points to the server. This is how the SSL certificate checks to ensure that there are no man in the middle attacks being perpetrated. The rest of the information is arbitrary.
Lastly, button up the permissions of our cryptographically generated key:
chmod o= /etc/postfix/smtpd.key
How to Configure Saslauthd for our Linux Mail Server
The Simple Authentication and Security Layer authentication daemon (Saslauthd) is a system service that handles plaintext authentication requests securely by inserting a security layer between the protocol and the connection. In layman’s terms, this provides security for connections that exchange usernames and passwords in plain text such as POP3 and IMAP.
First, we have to give it a place in which to operate. As with most Linux systems, we’re going to use the spool directory under /var/, and create a directory just for use with Postfix, then create another set of directories for saslauthd:
mkdir -p /var/spool/postfix/var/run/saslauthd
Next, we have to tell the saslauthd daemon to use our newly created directory. So, we’ll edit /etc/default/saslauthd, and navigate to the bottom line, and change this line:
OPTIONS="-c -m /var/run/saslauthd"
OPTIONS="-c -m /var/spool/postfix/var/run/saslauthd -r"
Next, we need to tell pam.d to use MySQL for authentication during SMTP transactions. (This requires that SMTP senders have a valid account before being able to send email, and is a vital step in protecting your email server from spammers. Create the file /etc/pam.d/smtp, and put the following lines in it:
auth required pam_mysql.so user=postfixadmin passwd=thepostfixadminpassword host=127.0.0.1 db=postfix table=mailbox usercolumn=username passwdcolumn=password crypt=1 account sufficient pam_mysql.so user=postfixadmin passwd=thepostfixadminpassword host=127.0.0.1 db=postfix table=mailbox usercolumn=username passwdcolumn=password crypt=1
This tells the saslauthd daemon to use MySQL for authentication, defines the username, password, server, database, table, and column where the credentials are kept, and lastly, tells it what type of cryptology to use when attempting to match passwords. Now, we have to tell Postfix to use saslauthd for these transactions.
We’re almost done with the file at this point, we just need to tell saslauthd to start automatically. Find the START directive in /etc/default/saslauthd, and change it from no to yes.
Edit /etc/postfix/sasl/smtpd.conf, and put the following lines in it:
pwcheck_method: saslauthd mech_list: PLAIN LOGIN CRAM-MD5 DIGEST-MD5 NTLM allow_plaintext: true auxprop_plugin: sql sql_hostnames: 127.0.0.1 sql_user: postfixadmin sql_passwd: thepostfixadminpassword sql_database: postfix sql_select: select password from mailbox where email = '%u'@'%r'
The first line tells Postfix to use saslauthd for authentication, the next line tells it that plaintext authentication is allowed (because saslauthd will encrypt it for us!), the rest of the entries tell Postfix / saslauthd how to ask MySQL for information to confirm the credentials.
Now, we’ll add the user postfix to the system, and make it a member of the sasl group so it has permissions to use sasl:
adduser postfix sasl
Now, let’s restart both of the services so our new settings will take effect:
/etc/init.d/postfix restart /etc/init.d/saslauthd restart
Enabling IMAP and POP3 Access with Courier
Courier is a separate MTA, which is frequently used in conjuction with Postfix to provide access to mailboxes via a client. Simply put: Postfix sends and receives mail to the server, but Courier provides access so the mail can be downloaded to your email client. Courier provides a number of services such as ESMTP, IMAP, POP3, LDAP, SSL, and HTTP mail connectivity.
Enabling IPv4 Only SSL Connectivity
IPv6 is the future, but it is a non-implemented future. Courier has already embraced the IPv6 realm and decided that, by default, if you are going to connect to it via SSL, you’ll have to do it via IPv6. For now, that is not very useful for us. So, we have to force it to use the IPV4 address everyone is used to.
To Force Courier to use IPv4 for IMAP, edit /etc/courier/imapd-ssl, and change the SSLADDRESS directive to the IPv4 IP address of the network adapter.
Repeat this process for the pop3d-ssl config file:
Enabling SMTP SSL Send Connectivity
By default, Postfix recieves email on port 25. We also want to enable it to receive mail using SSL on port 465 (the default SMTPS Port). To do so, we just need to uncomment the following lines (17-22) from /etc/postfix/master.cf:
smtps inet n - - - - smtpd -o smtpd_tls_wrappermode=yes -o smtpd_sasl_auth_enable=yes -o smtpd_client_restrictions=permit_sasl_authenticated,reject -o milter_macro_daemon_name=ORIGINATING
Now, just reload and restart Postfix so the settings will be applied:
postfix reload /etc/init.d/postfix restart
Like all the other services we have configured thus far, we need to tell Courier to use MySQL fr authentication. To do this, edi the following file: /etc/courier/authdaemonrc, and find the authmodulelist directive (on or about line 27). The default is authpam, but we need to change it to authmysql:
Save the file.
Now, let’s configure the MySQL authentication module by editing /etc/courier/authmysqlrc. Delete the existing contents of the file so that we are starting anew. (If you had a working configuration before, consider backing up the file before making this change). The entirety of the file’s contents should be:
MYSQL_SERVER localhost MYSQL_USERNAME postfixadmin MYSQL_PASSWORD thepostfixadminpassword MYSQL_PORT 0 MYSQL_DATABASE postfix MYSQL_USER_TABLE mailbox MYSQL_CRYPT_PWFIELD password #MYSQL_CLEAR_PWFIELD password MYSQL_UID_FIELD 5000 MYSQL_GID_FIELD 5000 MYSQL_LOGIN_FIELD username MYSQL_HOME_FIELD "/home/vmail" MYSQL_MAILDIR_FIELD CONCAT(SUBSTRING_INDEX(username,'@',-1),'/',SUBSTRING_INDEX(username,'@',1),'/') #MYSQL_NAME_FIELD MYSQL_QUOTA_FIELD quota
Setting Up Correct SSL Certificates
When you installed Courier, it generated some self-signed SSL certificates for localhost, but that will cause problems with mail delivery on most clients. So, we need to change that server name in the certificates to the fully qualified domain name for this mail server.
Change the IMAP Server Name
- Edit /etc/courier/imapd.cnf
- Find the Canonical Name Entry (CN=) and insert your FQDN for the mail server.
- Save the file.
Change the POP3 Server Name
- Edit /etc/courier/pop3d.cnf
- Find the Canonical Name Entry (CN=) and insert your FQDN for the mail server.
- Save the file
Now, we’ll need to delete and re-create the certificates for the IMAP and POP3 servers, and then restart Courier:
cd /etc/courier rm -f /etc/courier/imapd.pem rm -f /etc/courier/pop3d.pem mkimapdcert mkpop3dcert /etc/init.d/courier-authdaemon restart /etc/init.d/courier-imap restart /etc/init.d/courier-imap-ssl restart /etc/init.d/courier-pop restart /etc/init.d/courier-pop-ssl restart
As a side note, I create a script in /usr/local/sbin called restart-courier, which executes all the restarts above in the correct order to facilitate making changes to the system. You can download a copy of restart-courier here.
Setup the Postmaster Address
To be RFC Compliant, (and to ensure we get important system messages), we’ll need to modify the /etc/aliases file to route root and postmaster mail properly.
Edit the /etc/asliases file and ensure that the postmaster: root entry exists. This routes all “postmaster” mail to the “root” user.
Now, let’s route all the “root” mail to your email address (or the system administration address) by modifying the entry for root:
should be changed to:
Now, save the file, and exist the editor. Now, let’s tell Postfix to re-analyze the /etc/aliases file by running: newaliases, and then restart Postfix:
newaliases /etc/init.d/postfix restart
Testing Your Mail Server.
Testing Your Ability to Add Domains and Users to the system.
- Log into Postfixadmin, and create a new domain for the system. (example.com)
- Create a new mailbox for that domain. (firstname.lastname@example.org)
- Once the user is created, you should see that example.com has been created under /home/vmail/. If this fails, make sure that Postfix is running as the correct user and that the servics have been restarted appropriately to make all changes to the configs take effect.
In the example below, you can see the mailbox structure:
- The username
- The domain name to which that username belongs
- The mailboxes (current messages, new (unread) and tmp (draft))
Testing SMTP Connectivity
SMTP has to be working in order to receive mail. Let’s test to make sure everything is in order:
- Go to MXToolbox.com
- In the testbox, enter smtp:[Server IP Address]
You should get results like the one below:
If you notice, this configuration does give us a warning that the reverse DNS does not match the SMTP banner. There are two resolutions to this. If you are running a dedicated mail server, and this is the primary mail server, call your ISP and ask them to put a pointer record on your account so the rDNS does, indeed, match up with your domain name. Alternatively, (or if you are running a secondary mail server with multiple hosts), you can just modify main.cf to put your rDNS in the banner:
- Edit /etc/postfix/main.cf
- Change the smtpd_banner directive to show the same rDNS that MXToolbox shows. In many cases, it will be an IP address separated by hyphens, followed by the FQDN of the node of your provider. 172-165-185-100-yourcity-abbrev-yourisp.tld.
Testing Mailbox Deliverability
Your server may be up and running, but we need to confirm that mail can be delivered to a mailbox. We already added a domain and a mailbox to the system above, so now, let’s test and make sure mail can be directly delivered to that mailbox. To do this, we’ll use smtptest (a command line, Windows Program). Once you download and extract the .exe file, use the following syntax to sent a test email directly to your new mail server:
smtptest email@example.com firstname.lastname@example.org server=mail.server.com
Notice that we got a queued as serial number. This indicates that the message was successfully recieved by the system, the mailbox was found, validated, and available, and the message has been queued for delivery.
Testing Mail Retrievability
By now we know:
- The server is online and listening.
- Mailboxes are created in the system properly via Postfixadmin.
- We can deliver mail to the system and it is queue for delivery to a user / mailbox.
Now, we need to answer the question: Can I retrieve mail from the server?
To test this functionality, we are going to use www.mail2web.com.
- Navigate to www.mail2web.com.
- Click on Advanced Login.
- Enter in the IP Address of the server, the email address of the test account, and its password.
If you have configured everything correctly, it should log in and you’ll see your welcome email and the test email we sent with smtptest. However, if your are getting a failure here, it is easy to debug.
There are two types of failures that I see a lot: SASL failures and MySQL failures. (Read: “SASL LOGIN authentication failed: no mechanism available” and “authentication failed: authentication failure”. The former happens when Postfix cannot properly communicate with saslauthd, and the latter happens when saslauthd cannot properly communicate with MySQL.
Before you do anything else, in order to see what is happening, you need to:
- Add the entry log_level:10 to /etc/postfix/sasl/smtpd.conf. This enables you to see the SQL that goes on during authentication. This shows up in /var/log/auth.log.
- Add -v to the smtpd application command line in master.cf. (See: Making Postfix more Verbose)
How to Debug Login Failures
In the shell for the mail server, type:
tail -f /var/log/syslog
This will show you a continuous display of the log for the mail server. Once this is running, try to log in again via mail2web. If there are any errors, they will display here.
In the example above, you can see that pop3d and imapd both have an “authentication error: Input/output” error. This means that both of those services are having a hard time talking to MySQL to get information about a user credential. So, we’ll double check our configs for that part of the setup.
- Verify /etc/courier/authdaemonrc has authmodulelist=”authmysql” enabled.
- Verify /etc/courier/authmysqlrc has the correct username and password for MySQL
In this case, both were correct. So, we’ll need to turn on debugging. In /etc/courier/authdaemonrc, find the DEBUG directive, and set it to “3″
Now, we’ll restart Courier using our restart-courier script, and then re-check the syslog while we log in:
Now, you can see the error is with the SQL query we are using to authenticate users. This is contained in the /etc/courier/authmysqlrc file. Upon closer inspection, we can see that the copy / pasted SQL query contains special characters for single and double quotes. So, we’ll re-type the single and double quotes so that they are the correct, ASCII versions of the character, not a font version of the character.
Once we’ve done that, we’ll save the file and restart courier using our restart-courier script. Now, when we test again, we can log straight in!. Before we complete this part of the debugging process, don’t forget to turn DEBUG_LOGIN back to 0 in the /etc/courier/authdaemonrc file, and restart-courier once more.
Testing Email Client Connectivity
Now, let’s configure Thunderbird to make sure that we can send and receive mail (before we tell users and / or clients that they can start setting up their mail accounts!)
- Start Thunderbird Email Client.
- Click Edit > Account Settings
- Click Account Actions > Add New Account
- Enter Your name, email address, and password, then click Continue. The program will begin to search for your mail settings. Once this process begins, click Manual Config.
- You will be presented with an SSL Certificate “Security Exemption” screen. This screen is shown to you because we are using a free, self-signed certificate. The SSL cert is just as valid for safety and encryption as a for-pay certificate; however, because there is no Certificate Authority (CA) to validate it as “true and real” you have to do it manually. Click the Confirm Security Exception Button.
- At this point, you should see some emails starting to flow in. Try to create a new email, and send it to an external address (like a gmail address). When that email arrives at your gmail address, it will prove that your send capabilities are completely working.
- You may get an error telling you that you cannot send. If that is the case, close the test message you just composed, and search your open windows for another SSL Certificate Security exemption prompt like you saw in step 5 above. Sending via SMTPS uses SSL, and since that certificate is both different from the previous one you accepted and self-signed, you have to confirm you want to use it to send. Once you have confirmed it, create a new message, resend, and it should go out just fine.
If you are finding that you have other errors than the common issues covered in this article, be sure to sign in using your Facebook account, and leave a comment asking for help. But, before you do, make sure that you have used the tail -f /var/log/syslog command to capture the logging output of the mail server because that’s the first thing I’m going to ask for. If you’re feeling especially saucy, you could always Google it before you ask.