Mail/Web Server Setup

mail_server.sdf : 0.1 (draft)
Richard W. Brown
3 July 2008

There should be a blue line here

Table of Contents

There should be a blue line here

1. Introduction

I wrote this HOWTO after following many other howtos for Postfix and finding that parts did not work or did not explain how things worked. In short I spent many hours installing and reinstalling, playing around with settings and generally having fun. (I need to get a life) I wrote this HOWTO as record of what I did to get my mail server up and running. So I can in the future follow these steps again and rebuild my own mail server.

We will run through the setup of this one step at a time, hopefully not making any huge steps. As each server or service is added and built up. You will be able to test it is working as we move closer to our goal.

I am not a Linux expert or security guru so there are probably gaping holes in the security of this server. Which Ideal deal with as I find them or they are pointed out . Hopefully this will help you get your own server up and running.

1.1. Copyright

Copyright (c) 2008 by Richard W. Brown

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the license is available from http://www.fsf.org/licenses/fdl.html.

1.2. Disclaimer

No liability for the contents of this document can be accepted. Use the concepts, examples and information at your own risk. There may be errors and inaccuracies which could be damaging to your system. Proceed with caution, and although this is highly unlikely, the author(s) do not take any responsibility.

Owners hold all copyrights, unless specifically noted otherwise. Use of a term in this document should not be regarded as affecting the validity of any trademark or service mark. Naming of particular products or brands should not be seen as endorsements.

This document is how I configure and use the various software tools related to my own system. I am not, nor do I pretend to be a Linux expert. I am just some guy who has benefited from the expertise of others and wish to add my contribution back to the Linux community.


Note: You are strongly recommended to take backup copies of all files before they are modified.

1.3. Feedback.

Feedback is most certainly welcome for this document. Send your additions, comments and criticisms to the following email address: howtos at Mythical Beast dot co dot uk Errors and omission will be added to the next version of this document.

There should be a blue line here

2. WhatThis HOWTO Will Be Building.

2.1. Overview of the system.

The mail server this HOWTO will be building is called mail1. It is running as a VMware guest on a Ubuntu machine called linux32. Mail1 will be using the Hardy Desktop Edition of Ubuntu, I use it as it simpler to copy and paste between X than X and a terminal. X can be removed later if you really feel the need. I will use the domain name example.com throughout this HOWTO to be the domain name used on the Internet and a local domain of example.local for the machines behind the router/firewall on our LAN. I use .local as it will not clash any real world, Top Level domain (TLD).

2.2. Services provided by mail1

Mail1 will end up running the following servers and services.

There should be a blue line here

3. Basic Machine Config.

3.1. Creating Base VMware machine.

If you do not have VMware installed there are a number of very good posts on the Ubuntu forums

Create a new VMware machine. On my system I use the following:

3.2. Installing the Guest OS

Boot up your VMware machine and install Ubuntu Server. hen asked I install LAMP, Openssh server, For the harddisk I use ReisersFS with 8GB (hard drive vendors have a smaller value for 8GB to make themselves look better ) This still leaves 0.6 GB free for a swap partition.

To the basic installation I do the following to make it more convenient for me to use.

3.2.1. Post Install Configuration

I always do a couple of tweaks to the default install before making a copy. Since I have setup an apt-cacher package cache which saves time when you have two or more machines. You can get the packages locally, and not over the LAN but much much quicker than downloading them down ADSL.

See how I set up apt-cacher proxy server

As root create and then edit the file /etc/apt/apt.conf.d/01proxy

Client Settings for apt-cacher
sudo gedit /etc/apt/apt.conf.d/01proxy 
Acquire::http::Proxy "http:/linux32:3142"; 

Bring the OS up to date and fully patched. Do this before installing the VMware tools, if the kernel is updated during the upgrade you will only have to install the tools again.

Code:
sudo apt-get update 
sudo apt-get upgrade 

3.2.2. Network Interface

I've found that when I clone a VMware virtual machine, and then launch the clone, I have to tell the Ubuntu 7.04 server what its new MAC address is. To confirm that is needed, log in to the server and type:

ifconfig

If you don't see the eth0 network interface listed on the left side of the screen then in the host open the virtual machine\u2019s .vmx file in a text editor. Take note of the address in the line:

ethernet0.generatedAddress = "(MAC address)"

Then, back in the server type:

sudo nano -w /etc/iftab

This will open the iftab file in the nano text editor (the \u201c-w\u201d disables all wrapping of text). Change the MAC address for eth0 to the address from the .vmx file:

eth0 mac (MAC address) arp 1

and save the changes:

Restart the server.

3.2.3. Time synchronization.

If you do not run vmtools then simple run ntp and point it at the host. Job done!

To set up a local machine to access the host machine for the vmware machine. We need to point a the guest ntp at the local server. Restrict access, so nothing can read the client as it is the bottom of the chain and ... Well actually that is it.

/etc/ntp.conf
driftfile /var/lib/ntp/ntp.drift 
# This is our local time server talk to it in preference to the others listed 
server vmwarehost 
restrict 127.0.0.1 
restrict -4 default kod notrap nomodify nopeer noquery 
restrict -6 default kod notrap nomodify nopeer noquery 

3.3. Backup this default install.

Shut down the VMware machine and make a full copy of the directory. You can just make another and use it next time you want to play around with a Server machine on Ubuntu.

3.4. Configuring openssh

Packages that were installed
sudo apt-get install openssh-server openssh-client 

I also install openssh so I can ssh into the new machine and more than one terminal open at a time. I configure this so I can login without a password from linux32 to the mail server but not the other way round. I also use a different password on linux32 and mail1. At this point you can use ssh login to mail1 from linux32. You will need to answer yes and then enter the password for the user you setup on that machine.

Code:
ssh  mail1user@mail1 
OR 
ssh mail1 -l mailuser 

Code:
ssh-keygen -t rsa 
cd ~/.ssh 
cp id_rsa.pub authorized_keys 
chmod 600 ~/.ssh/authorized_keys 

You need to copy from your user on linux32 the contents of the file /home/<useronlinux32/.ssh/id_rsa.pub and paste it into the file on mail1 in that users .ssh directory called authorized_keys. If you did this right you can now ssh from linux32 to mail1 without using a password.

3.5. Network Setting

Code:
sudo gedit /etc/network/interfaces /etc/hosts 

/etc/network/interfaces
# The loopback network interface 
auto lo 
iface lo inet loopback 
 
# The primary network interface 
auto eth0 
iface eth0 inet static 
address 192.168.0.10 
netmask 255.255.255.0 
network 192.168.0.255 
gateway 192.168.0.1 

/etc/hosts
127.0.0.1      localhost localhost.mythicalbeast.local 
192.168.0.10   vmhardyserv  vmhardyserv.mythicalbeast.local 

You should be able to simply restart networking, but I found that did not work so I reboot and that does work. One day I may find out why.

Code:
sudo /etc/init.d/networking restart 

There should be a blue line here

4. Now For the BIG BANG Software install

We will start by installing all the software. This may take some time to download and install so go get cup of coffee or tea or beer or what ever you drink.

4.1. Installing Postfix and mailx

Packages that were installed
sudo apt-get install postfix postfix-mysql mailx 

When prompted choose Internet, the host name should get automatically worked out for you but should be mail1.example.com. I also install mailx as I like to use it for simple and easy testing.

4.2. Installing MySQL Server.

If you did not already install mysql server do so now as we will be using it as the backend storage.

Packages that were installed
sudo apt-get install mysql-server mysql-client 

4.3. Installing PCourier for POP3 and IMAP

These an all be installed on one line. They would not display nicely so I put them on two lines.

Packages that were installed
sudo apt-get install courier-base courier-authdaemon courier-authlib-mysql courier-imap 
sudo apt-get install courier-imap-ssl courier-ssl courier-pop courier-pop-ssl 

When asked about creating Web directories I answer No and do not worry about the wanring regarding configuring courier-ssl.

4.4. Installing Authentication and Encryption

If you want to configure ability to encrype and authenticate users and emails while a user is off site this is where we install the software.

Packages that were installed
sudo apt-get install postfix-tls libsasl2 libsasl2-modules libsasl2-modules-sql openssl 
sudo apt-get install libsasl2-modules-sql libgsasl7 libauthen-sasl-cyrus-perl 

4.5. Installing Anti-Virus and Spam Stoppers

If you want to scan incoming email for viruses and spam:

Packages that were installed
sudo apt-get install amavisd-new spamassassin spamc clamav clamav-daemon spamc libclamav3 clamav-freshclam 
sudo apt-get install postgrey arj lha unzip zoo 

4.6. Installing SquirrelMail

Packages that were installed
sudo apt-get install squirrelmail squirrelmail-locales php-pear php5-cli 

4.7. Installing phpmyadmin

Packages that were installed
sudo apt-get install phpmyadmin 

Select apache2 when asked which Web server you whant to configure.

There should be a blue line here

5. Configuring Servers and Utility Software.

5.1. Initial Configuration For Apache

When you stop and start your Apache server you will no doube see an erro message like the one below. Lets start by getting that sorted out.

Example Error Message
apache2: Could not determine the server's fully qualified domain name, using 192.168.0.10 for ServerName 

Apache cannot work out the domain name of your server machnice or perhaps you simply do not have a domain name setup. Not to worry it is simple to fix. Edit /etc/apache2/apache2.conf add the ServerName option. Use the output from the Linux command uname -n as the value. I add the line after ServerRoot. Then restart the apache server and you are done. So for my example server called linux32 we would do the following.

Code:
uname -n 
mail1     # <<== output from the uname -n command 
 
sudo gedit /etc/apache2/apache2.conf 
 
ServerRoot "/etc/apache2"    ## <<== find this line and add the one below 
ServerName "mail1" 

Do not forget to reload or restart Apache.

Code:
sudo /etc/init.d/apache2 restart 

5.1.1. Access Your Web Site Locally And From The Internet.

You now have Apache serving pages locally on your LAN, but you also want to be able to access the same Web site via the Internet. With Apache it is simple, once you know how

Load up the file in your favorite editor and add the following to tell Apache to serve the pages to the default site when accessed via two different IP addresses.

Code:
sudo nano /etc/apache2/sites-available/default 

Code:
 
NameVirtualHost 192.168.0.2 
NameVirtualHost 1.2.3.4 
 
<VirtualHost 192.168.0.2 1.2.3.4> 
        ServerAdmin webmaster@localhost 
 
        DocumentRoot /var/www/example.com 
        <Directory /> 
 

Do not forget to reload or restart Apache. Now surf to your pages with in your LAN and outside via the internet.

Code:
sudo /etc/init.d/apache2 reload 

5.1.2. Checking the install works ok

Use a browser to see your web server now you will see "It Works" displayed. Use Any of the URLs below to test this out.

Code:
http://localhost 
http://127.0.0.1 
http://mail1 

5.2. Configuring phpmyadmin

We will start by making the phpmyadmin site available to Apache, We do that by making a link of the phpmyadmin apache.conf file to the sites-available directory.

Code:
sudo ln -s /etc/phpmyadmin/apache.conf /etc/apache2/sites-available/phpmyadmin 

And enable the site with the followingwhich creates a symbolic link for phpmyadmin to the sites-enabled directory.

Code:
sudo a2ensite phpmyadmin 

Test that all is still well with the Apache configuration files with the following command

Code:
sudo apache2ctl -t 

If there were no warnings or errors reload the files ready for a quick test, that phpmyadmin is now working.

Code:
sudo /etc/init.d/apache2 reload 

You can now go to http://example.com/phpmyadmin/, and login with the root user you created for MySQl when it was installed.

5.3. Configuring MySQL

So we have a nice new but very empty Msql server. We need to create a database and then put our tables into the database. You can use the comand line or phpmyadmin now you have installed it. If you use phpmyamin just create the database and tables as detailed. I will not be explaining how to use it.

5.3.1. Configure MySQL

WE will edit the system Mysql my.cnf file to check on access and set some logging.

Code:
sudo nano /etc/mysql/my.cnf 

We want to bind to 127.0.0.1. Thisa means there can be no connections from remote machines, this is what we want. This should already be set as default.

Code:
bind-address = 127.0.0.1 

I find it is helpfull to see what the mysql DB is doing espicially in the early stages. Use this option to start the loging of any calls that are made to MySQL. It is probably commented out.

Code:
log = /var/log/mysql/mysql.log 

Then in a few weeks comment it out when everything is working, as it slows mysql down

Do the now normal restart to take the changes into use.

Code:
sudo /etc/init.d/mysql restart 

5.3.2. Creating the Database.

To create a database is very simple from the command line. We will call it 'postfix' as it is for postfix and I like to keep things simple.

Code:
mysqladmin -u root -p create postfix 

When you run the command above you are asked for a password. It is the Mysql password for root, which is not the same as the root linux user password.

5.3.3. Creating our User.

We will be needing a user with restricted permissions to access the tables for lookups. This user will only need to SELECT data never INSERTing or UPDATEing. From the command line we will open up a session.

Code:
mysql -u root -p 

Code:
GRANT SELECT ON postfix.* TO mail@localhost IDENTIFIED BY 'your-password'; 

This will create a new user called mail who just has SELECT access to our database. To get these new permissions noticed by Mysql you need to flush.

Code:
flush privileges; 

If you are intending on using Squirrelmail asa web front end to allow users to create, amend and delete thier alaises or change their passwords. Then we need to give mail some extra privileges. We will do it now while we are here. Use the line below from the command line and the flush the privileges again.

Code:
GRANT SELECT, INSERT, UPDATE, DELETE ON postfix.* TO mail@localhost IDENTIFIED BY 'your-password'; 

5.3.4. Creating the Tables.

Now we have created the database we need sopmething to put our data into. We will be creating three initial tables.

Table: Domain
Name Charactistics
Rows:  
domain VARCHAR(50) NOT NULL
Indexes:  
PRIMARY KEY domain
Table: Alias
Name Charactistics
Rows:  
from VARCHAR(50) NOT NULL
to VARCHAR(200) NOT NULL
Indexes:  
PRIMARY KEY from
Table: User
Name Charactistics
Rows:  
email VARCHAR(50) NOT NULL
name VARCHAR(50) NOT NULL
password VARCHAR(20) NOT NULL
Indexes:  
PRIMARY KEY email

To get these created on our database copy the followinginto a file and then run the command line. We will use this mothod for adding some default users later.

Code:
USE postfix; 
 
DROP TABLE IF EXISTS domain; 
DROP TABLE IF EXISTS alias; 
DROP TABLE IF EXISTS user; 
 
CREATE TABLE domain ( 
domain VARCHAR(50) NOT NULL, 
PRIMARY KEY (domain) 
); 
 
 
CREATE TABLE alias ( 
source       VARCHAR(50)  NOT NULL, 
destination  VARCHAR(200) NOT NULL, 
PRIMARY KEY (source) 
); 
 
 
CREATE TABLE user ( 
email        VARCHAR(50) NOT NULL, 
name         VARCHAR(50) NOT NULL, 
password     VARCHAR(20) NOT NULL, 
PRIMARY KEY (email) 
); 

Code:
mysql -u root -p < update_postfix.sql 

5.3.5. Create postfix map files for MySQL

We are going to create a bunch of map files that tell Postfix how to get the information out of the Mysql database. They are faily simple and I am sure you will work out how they do the mapping without explaination. In each file change <mysqlpasswd> to be what you used as your password for the MySQL user mail. Also, when setting the hosts value do not use localhost, 127.0.0.1. Whicjh although it is also localhost it will force postfix to use TCP/IP and not a local socket. This will allow you to run Postfix chrooted and is slightly more secure.

5.3.5.1. mysql_domains.cf

How to find valid domains within our system.

Example:/etc/postfix/mysql_domains.cf
user = mail 
hosts = 127.0.0.1 
dbname = postfix 
password = <mysqlpasswd> 
table = domain 
query = SELECT domain FROM domain WHERE domain = '%s' 

5.3.5.2. mysql_alias.cf

This maps aliases to real email addrersses. This means that one destination can have many email addresses. E.g one person looks after all sales and support. So for that user with an email address of tired.slave@example.com there would be two entries one from sales@example.com and a second from info@example.com. It can also be used as an anti-spam system when ever you deal with a new company simply create a new email alias from_<comapny>@example.com. If you start getting spam on that address you know they have sold your addrerss on. You can remove the listing and no more spam from them.

Example:/etc/postfix/mysql_alias.cf
user = mail 
hosts = 127.0.0.1 
dbname = postfix 
password = <mysqlpasswd> 
query = SELECT destination FROM alias WHERE source = '%s' 

5.3.5.3. mysql_mailbox.cf

As our email users will not all have linux accounts and therefore will not have home directories we need a way to tell Postfix where to deliver their emails to. This mapping does that. We will set a top level directory later for where email will be stored. This part is at the lower end or the subdirectory where the Maildir structure will begin. For each user it will be TOP_LEVEL/<domain/<email_name>/>. Following the Postfix specification, we put a '/' at the end to tell Postfix it is a Maildir and not a mbox file.

Example:/etc/postfix/mysql_mailbox.cf
user = mail 
hosts = 127.0.0.1 
dbname = postfix 
password = <mysqlpasswd> 
query = SELECT CONCAT(SUBSTRING_INDEX(email,'@',-1),'/',SUBSTRING_INDEX(email,'@',1),'/') FROM user WHERE email = '%s' 

5.3.5.4. mysql_emailself.cf

This mapping table is used as part of the virtual_alias_maps mapping and saves you having to map every user back to themselves. Why would you ned to do that? You ask. See below it is to do with the way catch all addresses work.

Example:/etc/postfix/mysql_emailself.cf
user = mail 
hosts = 127.0.0.1 
dbname = postfix 
password = <mysqlpasswd> 
query = SELECT email FROM user WHERE email = '%s' 


Note: As these lookup tables all contain passwords in open text they should not be world readable. We can do that by restricting the group are removing all world permissions.

Code:
sudo chgrp postfix /etc/postfix/mysql_*.cf 
sudo chmod 640 /etc/postfix/mysql_*.cf 

Aliases are the mechinism that allows mail to be delivered in a very flexible way with a very simple setup. That is the users get their mail and you don't have too much extra work.

Let us look at a fictious example:

Domains
example com
another co.uk
Users
fred example.com
bert another.co.uk
Alias
Source Destination
@example.com bert@another.co.uk

An email arrives addressed to "sales@example.com". Postfix looks in the alias mappings and searches for sales@example.com. It does not find one, so it searches for @example.com, which is the way to specify a "catch all" address for a domain. It finds an entry and gets the destination is bert@another.co.uk. Postfix goes on to search bert@another.co.uk and finds one. This time the destination is the same as the mail, therefore it is the final destination. The mail can therefor be delivered. Another lookup in the domain table finds this is a local domain so the mail is send to the Maildir mail box.

Now you can see why the mysql_emailself.cf save you work.You never have to create a mapping user@domain.tld back to user@domain.tld. It is done automatically.

You will also need some aliases for webmaster, postmaster and abuse. I also add one for root on the loalhost for when cron and other system processes need to report stuff.

FIXME, need more examples here.

5.4. Create a vmail user

As the receipient, for the mail that will have a final destination here, does not require a Linux account some users will not have any home directory to store mails. It is therefore wise and less work to create a virtual user for all incomming mail.

Code:
sudo groupadd -g 5000 vmail 
sudo useradd -g vmail -u 5000 vmail -d /home/vmail -m 

5.5. Configuring Postfix (main.cf)

Postfix uses the file /etc/postfix/main.cf for its configuration. One thing to remember is that Postfix has hundreds of parameters and options all of which have sensible default values. If you are going to use the default do not set the option or your main.cf will be too longand confusing to handle.

The settings below are the ones I use for my mail server. For me it is a good end point for you it is, at least, a starting point. You will probably want to customise it to your own system.

FIXME need to explain about the format of postfix config files.

Code:
mydomain = example.com 
myorigin = $mydomain 
myhostname = mail1 
mydestination = mail1, localhost.localdomain, localhost 
mynetworks = 127.0.0.0/8 192.168.0.0/24 !192.169.0.1 
 
inet_interfaces = all 
 
virtual_alias_domains = 
virtual_alias_maps = mysql:/etc/postfix/mysql_alias.cf 
                     mysql:/etc/postfix/mysql_emailself.cf 
virtual_mailbox_domains = mysql:/etc/postfix/mysql_domains.cf 
virtual_mailbox_maps = mysql:/etc/postfix/mysql_mailbox.cf 
virtual_mailbox_base = /home/vmail 
 
# This is the GID and UID for the virtual user we setup 
virtual_uid_maps = static:5000 
virtual_gid_maps = static:5000 
 
# to reject unknown recipients in a "nice" way 
# set local_recipient_maps to virtual_mail_box_maps 
#local_recipient_maps = $virtual_mail_box_maps 
biff = no 
 
# appending .domain is the MUA's job. 
append_dot_mydomain = no 
 
# Uncomment the next line to generate "delayed mail" warnings 
#delay_warning_time = 4h 
 
readme_directory = no 
 
# TLS parameters 
# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for 
# information on enabling SSL in the smtp client. 
#broken_sasl_auth_clients = yes 
smtpd_sasl_auth_enable = yes 
smtpd_sasl_path = smtpd 
smtpd_sasl_local_domain = $mydomain 
 
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache 
 
smtpd_tls_security_level = may 
smtpd_tls_loglevel = 2 
smtpd_tls_cert_file = /etc/postfix/smtpd.cert 
smtpd_tls_key_file = /etc/postfix/smtpd.key 
smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu) 
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache 
smtpd_recipient_restrictions = reject_unauth_pipelining, permit_mynetworks, 
                               permit_sasl_authenticated, reject_non_fqdn_recipient, 
                               reject_unknown_recipient_domain, reject_unauth_destination, 
                               check_policy_service, inet:127.0.0.1:60000, permit 
 
# modify the existing smtpd_sender_restrictions 
smtpd_sender_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_non_fqdn_sender, 
                            reject_unknown_sender_domain, reject_unauth_pipelining, permit 
alias_maps = hash:/etc/aliases 
alias_database = hash:/etc/aliases 
relayhost = 
mailbox_size_limit = 0 
recipient_delimiter = + 
 
content_filter = amavis:[127.0.0.1]:10024 
receive_override_options = no_address_mappings 
 

I suggest you take a time out here and read the documentation on these settings before proceeding further.

5.6. Restart Postfix

Code:
sudo /etc/init.d/postfix restart 

When you have changed main.cf or any of the mysql mapping files you can use the reload command as it is not necessary to restat Postfix at these times.

Code:
sudo postfix check 

After running the postfix check command if there are no warnings or errors then this part is done. Time for a coffee and streach your legs a little!

5.7. Configuring authenticated SMTP (Auth-SMTP)

Imagine your users fetch their email using POP3. Now they need a way to send mails back through your mail server. For security reasons Postfix allows users defined in mynetworks to send emails. Usually your mail server will only accept mails for its own domains. If you allowed everybody to send email to every other domain you would provide a so called open relay that spammers abuse to send out their digital trash. So the logical way is to make remote users trusted by letting them provide their username and password. If the credentials are correct the user will be trusted like he has an IP in mynetworks. Most email cilents have this feature included.

Setting up authenticated SMTP is quite easy. The only pitfall is that Debian runs Postfix in a chroot'ed environment in /var/spool/postfix by default.

5.7.1. Tell Postfix to use SASL/MySQL

As written earlier Postfix uses the Cyrus SASL library for authenticated SMTP. So you need to tell Postfix how to access the data storage that keeps the usernames and passwords. This is easy. You just need to create a file /etc/postfix/sasl/smtpd.conf like this:

Code:
pwcheck_method: auxprop 
auxprop_plugin: sql 
mech_list: plain login cram-md5 digest-md5 
sql_engine: mysql 
sql_hostnames: 127.0.0.1 
sql_user: mail 
sql_passwd: <mysqlpassword> 
sql_database: mail 
sql_select: select password from user where email='%u@%r' 

Important You know the drill. Use proper permissions on this file:

Code:
sudo chown root:postfix /etc/postfix/sasl/smtpd.conf 
sudo chmod 640 /etc/postfix/sasl/smtpd.conf 

(If you have trouble with SASL you may consider inserting a line like "log_level: 7" here. It will write more verbose information to the log files and perhaps help to find the cause.) Use TLS to encrypt SMTP traffic

An important step is to encrypt the SMTP session. Otherwise the username and password could be transmitted in a very insecure way if the mail client chose to use one of plaintext authentication methods). So I encourage you to encrypt that communication using TLS. TLS is short for Transport Layer Security (RFC2246) and in short terms uses SSL (Secure Socket Layer) which encrypts the mail connection between the road-warrior and the mail server.

First you will need an SSL certificate. If you don't want to pay for one from your favorite trustcenter you can well use a self-signed one. (Personal note: I wonder how paying for something makes it more trusted.) The only drawback: the mail client does not know about your CA (certificate authority) and will spit out a warning to the user. Either tell the users to ignore the warning or let them install the certificate on their computers. (Outlook does not allow the unknown CA to be ignored. You need to install the certificate to make it work.)

For a certificate that is valid for ten years for the hostname smtp.domain.tld you would type this:

Code:
sudo openssl req -new -outform PEM -out /etc/postfix/smtpd.cert -newkey rsa:2048 \ 
-nodes -keyout /etc/postfix/smtpd.key -keyform PEM -days 3650 -x509 

You will then be asked a few question about the fields of the certificate. It does not matter what you enter. Just fill the fields. One exception though - the "Common Name" must be the hostname of your mail server. Example session:

Code:
Country Name (2 letter code) [AU]:UK 
State or Province Name (full name) [Some-State]:Hampshire 
Locality Name (eg, city) []:Guildford 
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Dragon 
Organizational Unit Name (eg, section) []:IT Department 
Common Name (eg, YOUR name) []:smtp.example.com 
Email Address []:postmaster@example.com 

After a short moment you will get two files: "smtpd.key" (the private key file) and "smtpd.cert" (the certificate).

Security note Make sure at least the key file is not readable for the whole wide world:

Code:
sudo chown root:postfix /etc/postfix/smtpd.key 
sudo chmod 640 /etc/postfix/smtpd.key 

5.8. Configure the POP3 / IMAP service

You already set up a large part of the configuration. However your users will still be unhappy as they cannot reach their mailboxes. So it is time to configure the POP3 or IMAP service. First you need to edit the file /etc/courier/authdaemonrc and set the directive authmodulelist to "authmysql" like this:

Example:/etc/courier/authdaemonrc
authmodulelist="authmysql" 

Then you need to define the fields of the MySQL database table in /etc/courier/authmysqlrc like this:

/etc/courier/authmysqlrc
MYSQL_SERVER localhost 
MYSQL_USERNAME provider_admin 
MYSQL_PASSWORD ... 
MYSQL_PORT 0 
MYSQL_DATABASE provider 
MYSQL_USER_TABLE users 
#MYSQL_CRYPT_PWFIELD (comment this out) 
MYSQL_CLEAR_PWFIELD password 
MYSQL_UID_FIELD 5000 
MYSQL_GID_FIELD 5000 
MYSQL_LOGIN_FIELD email 
MYSQL_HOME_FIELD "/home/vmail" 
MYSQL_NAME_FIELD        name 
MYSQL_MAILDIR_FIELD CONCAT(SUBSTRING_INDEX(email,'@',-1),'/',SUBSTRING_INDEX(email,'@',1),'/') 

Code:
sudo chown daemon:daemon /etc/courier/authmysqlrc 
sudo chmod 660 /etc/courier/authmysqlrc 

Careful - the authmysqlrc is a bit picky. Make sure you have not accidentally inserted trailing spaces on the lines. (If you are editing the file in 'vim' this command should take care of that: :%s/\s\+$//g) Do not forget to restart the authdaemon process using /etc/init.d/courier-authdaemon restart. A quick test

Try to reach the POP3 service by running

Code:
telnet localhost pop3 
 
Trying 127.0.0.1... 
Connected to localhost. 
Escap 
e character is '^]'. 
+OK Hello there. 
quit 

Voila - your users should be happy now.


Note: You cannot fetch emails from a mailbox unless at least one mail has been sent there. Users would get cryptic error messages. So I recommend sending a welcome email to new users.

5.9. Test your setup

Congratulations. The configuration part is done. Now comes the more practical part. We will now create the database entries for your first domain so you can test to receive an email for the virtual domain. Please create these rows in the appropriate database tables:

Table: Domain
Column Value
domain virtual.test
Table: User
user
Column Value
email user@virtual.test
password secret

In MySQL speak this means entering the following two statements:

Code:
INSERT INTO domain (domain) VALUES ( 
   'example.local' 
); 
 
INSERT INTO user (email,password) VALUES ( 
  'mailtest@example.com', ENCRYPT('secret') 
); 

Code:
tail -fn90 /var/log/mail.log 
tail -fn100 /var/log/mysql/mysql.log 

This means we have one domain called "example.local" and one user whose email address (and also the username) is "user@example.local". The password for this user is "secret". As you do not have an MX entry (mail exchanger - part of the DNS zone) you need to 'deliver' the email manually. Establish an SMTP connection to your mail server (telnet servername smtp) and enter the SMTP commands written on the right side: Server You

220 myserver ESMTP Postfix (Debian/GNU)

ehlo workaround.org

250-mailtest 250-PIPELINING 250-SIZE 10240000 250-VRFY 250-ETRN 250-STARTTLS 250-AUTH LOGIN PLAIN DIGEST-MD5 CRAM-MD5 250-AUTH=LOGIN PLAIN DIGEST-MD5 CRAM-MD5 250 8BITMIME

mail from:<test@workaround.org>

250 Ok

rcpt to:<user@virtual.test>

250 Ok

data

354 End data with <CR><LF>.<CR><LF></LF></CR></LF></CR>

This is a test email.

250 Ok: queued as ABC1D1C123

quit

221 BYE

If the server responded like in the example dialog above then the email was at least received. In the log file /var/log/mail.log you should find a section like this:

Jul 24 21:48:28 myserver postfix/smtpd[9119]: connect from myserver[127.0.0.1] Jul 24 21:48:48 myserver postfix/smtpd[9119]: F2C1B47BD: client=myserver[127.0.0.1] Jul 24 21:48:52 myserver postfix/cleanup[9144]: F2C1B47BD: message-id=<20040724194842.F2C1B47BD@myserver> Jul 24 21:48:52 myserver postfix/qmgr[9117]: F2C1B47BD: from=<test@workaround.org>, size=313, nrcpt=1 (queue active) Jul 24 21:48:52 myserver postfix/virtual[9148]: F2C1B47BD: to=<user@virtual.test>, relay=virtual, delay=10, status=sent (delivered to maildir)

If you read "status=sent (delivered to maildir)" then the email has been successfully delivered. Run the command find /home/vmail to see all directories and files there. It should look like this:

/home/vmail/virtual.test /home/vmail/virtual.test/user /home/vmail/virtual.test/user/tmp /home/vmail/virtual.test/user/cur /home/vmail/virtual.test/user/new /home/vmail/virtual.test/user/new/1114511715.V801I7400b.my.server

Everyting worked like I described? Great. Then as a last test you may try to fetch the email from your mail client via POP3 or IMAP (depending on what service you installed). The username for fetching email is always the email address ("user@virtual.test") and the password is "secret" in this test case.

5.10. Populate your database

Now that the first test has succeeded you will want to configure the datase for your own domains and users. Let me explain what you need to insert into the database: For every new domain...

Insert the domain into the 'domains' table.

For every new user...

Insert a new row into the 'users' table containing the email address and the password (in plain text).

For every new forwarding...

Insert a new row into the 'forwardings' table containing the source (the address you send mail to) and destination email address (the address the mail gets forwarded to). If you have multiple destinations (like a poor-man's mailing list) you may list all email addresses in one row just separated by commas.


Note: this table is used on every email that passes your system. So you can even redirect local mail addresses.

Examples

source destination Effect postmaster@my.domain philip@my.domain

Redirect emails for postmaster to philip. @my.domain john@my.domain

Forward all email to email addresses in the domain my.domain to john.

This does not apply to users in the `email` table though (like tina@my.domain). So more specific users of a domain always have a higher precedence than these so called "catch-all" accounts.

@my.domain @another.domain

This is a whole domain redirection. Every email address in the my.domain domain will be directed to the same user at another.domain. So julie@my.domain will be redirected to julie@another.domain.

jesper@my.domain dilbert@my.domain,dilbert@gmail.com

Forward email that is sent to jesper@my.domain to the two email addresses listed on the right side. Both users get a copy.

5.11. Scanning Incoming Email For Viruses And Spam

5.11.1. Introduction to AMaViS

The two most annoying things when using email are spam and viruses. Fortunately you can fight both using a software called AMaViS (A Mail Virus Scanner). AMaViS is an interface between Postfix, spamassassin (famous for its bayesian spam filtering capabilities) and any virus scanner (like ClamAV which is freely available). Do not get confused: AMaViS contains the spam filtering part but has no virus scanner built in. I suggest you install ClamAV, too. It is a free virus scanner that gets updated frequently.

FIXME Need to rewrite this for the Ubuntu format where the files are split

Add your own domain name in here.

Example:/etc/amavis/05-node-id
$myhostname = "mail.example.com" 

Uncomment the two lines in the content filer file.

Example:/etc/amavis/15-content_filter_mode
@bypass_virus_checks_maps = ( 
   \%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re); 
@bypass_spam_checks_maps = ( 
   \%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re); 

Example:/etc/amavis/20-debian_defaults
 $sa_spam_subject_tag = '[**SPAM**] '; 

Example:/etc/amavis/50-user
@local_domains_acl = qw(.); 
$log_level = 2; 
$syslog_priority = 'debug'; 
$sa_kill_level_deflt = 8.0; # triggers spam evasive actions 
 
@lookup_sql_dsn = ( ['DBI:mysql:postfix' 'mail', '<mysqlpassword>'] ); 
$sql_select_policy = 'SELECT "Y" as local FROM domains WHERE CONCAT("@",domain) IN (%k)'; 
 
$final_spam_destiny = D_PASS; 
#$final_virus_destiny = D_DISCARD; 
#$final_banned_destiny = D_REJECT;  # what to do with attached exe com or doc files 

Code:
sudo chmod 640 50-user 
sudo chown root:amavis 50-user 

FIXME Need to come back here to sort out about the av-scanners set up in /etc/amavis/conf.d/15-av_scanners

Code:
sudo adduser clamav amavis 

Code:
sudo /etc/init.d/amavis restart 

5.11.2. Configuring ClamAV

With all that above done there is not much more to sort out for ClamAV. The configuration files are in /etc/clamav, but they are automatically generated, so do not edit them.

The daemon part of Calmav, freshclam, checks for anti-virus definition updates once per hour. Which does seem a little overthe top. Lets reduce that to twice a day.

Code:
sudo dpkg-reconfigure clamav-freshclam 

We need to set this up as the daemon, checking for updates twice per day and Yes we do want clamd to be notifed of any updates.

If needed, this will redefine the configuration with a lot of questions. Not needed unless you need to configure.

Code:
sudo dpkg-reconfigure clamav-base 

Please take a look at the /etc/amavis/amavisd.conf file. These settings need to be taken care of: Setting Meaning $mydomain = 'yourdomain.org'; You will find a reference to $mydomain quite often in the configuration file. So you know where you find it. If you do not use local domains I recommend you set it to 'localhost'. @bypass_virus_checks_acl = qw( . ); If this line is commented out (has a '#' at the beginning of the line) then virus checks are enabled. @bypass_spam_checks_acl = qw( . ); If this line is commented out (has a '#' at the beginning of the line) then spam checks are enabled. @lookup_sql_dsn = ( [ 'DBI:mysql:provider', 'provider_admin', '...' ] ); This information tells AMaViS how to access your database. It needs to query the domains table. You need to replace the '...' with your database access password again. See also the next entry. $sql_select_policy = 'SELECT "Y" as local FROM domains WHERE CONCAT("@",domain) IN (%k)'; AMaViS needs to know which domains are hosted on your server. When an email passes the mail server this setting is used to determine if the email is outgoing (sent by your system) or incoming (sent by someone on the internet). Outgoing email will not be scanned for viruses or spam. $final_virus_destiny = D_DISCARD; The default is to bounce infected mails. That is mostly useless because the mails are already received (Postfix has put them into the mail queue) and bouncing would mean to send back an error to whoever appears to be the sender of the email. Trust me - the real sender of a virus email is never the person who appears in the mail headers. Bouncing would mean you harass someone who is innocent. Don't. $final_banned_destiny = D_REJECT; This defines how to handle emails with banned attachment types. Many MIME types like PIF, EXE, COM or DOC files are infected. You may choose later which types you do not like. $final_spam_destiny = D_PASS; This defines what to do with emails that are classified as spam. You may wonder why I suggest you let these emails pass. My users would get upset if I just threw away emails that a machine has found to be spam. In any case a line "X-Spam-Status" is added to the mail header. So users can configure their email clients to handle mails differently depending on the spam status. $sa_tag_level_deflt = -1000; AMaViS rates every mail with a "spam score". Usually spam has levels of 5-10. You will get "X-Spam-Status" header lines added to the email if the spam score is above this value. I set it to -1000 because I want all mail to get the header lines. $sa_tag2_level_deflt = 5.0; If the spam score is higher than this value then the mail will be flagged as spam. This is done by adding a header line "X-Spam-Status: Yes". $sa_kill_level_deflt = 10; If the spam score is higher than this value AMaViS starts to take action on the mail. The action is defined by $final_spam_destiny. $sa_spam_subject_tag = '***SPAM*** '; If you like to have the email subject altered to make spam mails more visible then you can have it rewritten. This string will be added if spam is detected. @av_scanners = ( ... This is a section where you can configure one or more virus scanner. Many common scanners are already preconfigured and just need to have the comment sign ('#') removed from the lines. You are also free to add your own command-line virus scanner here. For the beginning I suggest you just enable ClamAV and comment out all other entries. You may wonder why clamav is mentioned twice. Well, the @av_scanners' entry is about the daemonized version (clamd) and the @av_scanners_backup's entry runs the command-line version (clamscan). $sa_local_tests_only = 0; Unless your email gateway is already completely overloaded I strongly recommend you enable remote tests. Postfix can only check if the IP address of the system it just received an email from is in a blacklist. SpamAssassin also does this for every host that the email went through. This increases your chance of finding out if the email went through a known spam relay. It also checks if URLs that are mentioned in the email are blacklisted. All this is done automatically if you do not restrict your server to local tests only.

Run adduser clamav amavis if you intend to use the clamd (the daemon variant of the ClamAV scanner). In any case remember to restart the amavis service to activate your changes (/etc/init.d/amavis restart). Tell Postfix to use AMaViS

Now that the amavis daemon is hopefully running in the background you still need to tell Postfix that you want to have all your emails scanned. This is done by setting the global content filter in your /etc/postfix/main.cf like this:

/etc/postfix/main.cf
content_filter = amavis:[127.0.0.1]:10024 
receive_override_options = no_address_mappings 

The content_filter entry makes all email be sent to a service called amavis which you will define in the next step. Next edit the /etc/postfix/master.cf and add these two services:

/etc/postfix/maaster.cf
amavis unix - - - - 2 smtp 
   -o smtp_data_done_timeout=1200 
   -o smtp_send_xforward_command=yes 
 
127.0.0.1:10025 inet n - - - - smtpd 
   -o content_filter= 
   -o local_recipient_maps= 
   -o relay_recipient_maps= 
   -o smtpd_restriction_classes= 
   -o smtpd_client_restrictions= 
   -o smtpd_helo_restrictions= 
   -o smtpd_sender_restrictions= 
   -o smtpd_recipient_restrictions=permit_mynetworks,reject 
   -o mynetworks=127.0.0.0/8 
   -o strict_rfc821_envelopes=yes 
   -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks 

5.12. Configuring Postgrey, Grey listing

The default config of postgrey is okay. However you need to tell Postfix to use it.

/etc/postfix/main.cf
sudo vi /etc/postfix/main.cf 

And then edit the recipient restrictions:

/etc/postfix/main.cf
smtpd_recipient_restrictions = reject_unauth_pipelining permit_mynetworks permit_sasl_authenticated 
                               reject_non_fqdn_recipient reject_unknown_recipient_domain 
                               reject_unauth_destination check_policy_service inet:127.0.0.1:60000 permit 

You can tweak whitelisting in /etc/postgrey. You can tweak postgrey configuration by tweaking /etc/default/postgrey. E.g. delay, auto whitelisting, or reject message.

host212-183-132-77.uk.access.vodafone.net

5.13. Squirrelmail Configuration

5.13.1. Apache Configuration

You need make a link from SquirrelMail configuration to apache site-available directory.

Code:
sudo ln -s /etc/squirrelmail/apache.conf /etc/apache2/sites-available/squirrelmail 

And enable with this:

Code:
sudo a2ensite squirrelmail 

I just use the default settings from Squirrelmail

Reload apache to activate changes. First test if ok.

Code:
sudo apache2ctl -t 

Then reload it.

Code:
sudo /etc/init.d/apache2 reload 

You can now go toyourdomain.com/squirrelmail/ or mail.yourdomain.com if you chose virtual host.

This should show a squirrel mail page. Log in wont work yet though.

Start configuring squirrel mail.

Code:
sudo squirrelmail-configure 

You can now go to yourdomain.com/squirrelmail/ or mail.yourdomain.com if you chose virtual host. This should show a squirrel mail page. Log in will now work. (Except you may not have defined users, check data section. And they may not have received an email which also means you can not view any IMAP info.)

5.13.2. Adding Plugins

There are two plugins I like to use with Squirrelmail.

Change SQL password - Allows anyone to update their own password when logged into Squirrel mail. Mail Aliases - Allow you to maintain your own aliases mappings.

5.13.2.1. Checking DB access module is loaded

Start by making sure that the Pear libraries are installed you will also require the MDB2 and MDB" mysql extension. You get install these extra software by following the lines below.

Use the pear list command to see which packages are installed you need to to have:

If you do not have then see below.

Code:
sudo pear list 
sudo pear install DB 
sudo pear install pear/MDB2 
sudo pear install pear/MDB2#mysql 

5.13.2.2. Change Passwords plugin.

Download change_sqlpass (not change_mysqlpass) from the Squirrelmail web site. Also get the latest "Compatibility plugin" You will need that too!

Unzip the compatibility plugin some where safe, like /tmp so you can read the README and INSTALL instructions.

When I installed it. I simply had to

Code:
cd /usr/share/squirrelmail/plugins 
sudo zxvf compatibility-2.0.11-1.0.tar.gz 

That was it .

Remove the software you unzipped into /tmp and unzip the change_sqlpass tar/zip file. Again read the README and INSTALL file. Follow the instructions.

This is what I had to do.

Code:
cd /usr/share/squirrelmail/plugins 
sudo tar zxvf /home/mailtest/change_sqlpass-3.3-1.2.tar.gz 
cd change_sqlpass 
sudo cp config.php.sample config.php 
sudo nano config.php 

The lines I changed are these

/usr/share/squirrelmail/plugins/change_sqlpass/config.php
$csp_dsn = 'mysql://mail:<mysqlpassword>@localhost/postfix'; 
$lookup_password_query = 'SELECT count(*) FROM user WHERE email = "%1" AND password = %4'; 
$password_update_queries = array('UPDATE user SET password = %4 WHERE email = "%1"', ); 
$password_encryption = 'MYSQLENCRYPT'; 
$csp_salt_static = '"XX"';                # See Note Below !! 


Note: If you use the salt line above then when you create new users you MUST encrypt the password that is stored into the MySQL database with the same salt. Use the ENCRYPT('password', 'XX'). Also use any two characters as the salt.

Save the changes you made and as this file has a password it should not be world readable so we change the group and permissions to suit.

Code:
sudo chown root:www-data  /usr/share/squirrelmail/plugins/change_sqlpass/config.php 
sudo chmod 640  /usr/share/squirrelmail/plugins/change_sqlpass/config.php 

Now we can run the squirrelmail config program and get the plugin taken into use.

Code:
sudo squirrelmail-configure 

Then navigate you way to the plugin selection screen. 8 Plugins. Find change_pass on the list of available plugins and enter the number. It should change to the top of the sceen under Installed plugins. Load up Squirrelmail goto the options link and follow the link to change password.

Remove the software you unzipped into /tmp.

5.13.2.3. Adding the Mail Alias plugin.

Download the mail_alias tar file from the Squirrelmail web site and unzip into /tmp. Read the README and INSTALL file. Follow the instructions.

This is what I had to do.

Code:
cd /usr/share/squirrelmail/plugins 
sudo tar zxvf /home/mailtest/mail_alias-2.0.0-1.4.4.tar.gz 
cd mail_alias 
sudo cp config.php.sample config.php 
sudo nano config.php 

The lines I changed are these

/usr/share/squirrel/plugins/mail_alias/config.php
$mailbox_dir = '/home/vmail/[DOMAIN]/[USERNAME]'; 
$max_alias = '-1'; 
$ma_db_dsn = 'mysql://mail:<mysqlpassword>@localhost/postfix'; 
$sql_get_user = 'SELECT email FROM  user' 
              . ' WHERE email = ?'; 
$sql_get_domains = 'SELECT domain FROM domain'; 
$sql_get_aliases = 'SELECT a.source' 
                  . ' FROM alias as a, users as u' 
                  . ' WHERE a.destination = ?' 
                  . ' AND u.email = a.destination'; 
$sql_add_alias_user = 'INSERT INTO alias (source, destination)' 
                    . ' VALUES (?, ?)'; 
$sql_add_alias_forward = 'INSERT INTO <forward-table> (<source_id-field>, <destination-fiel$ 
                       . ' VALUES (?, ?)'; 
$sql_del_alias_forward = 'DELETE FROM alias' 
                       . ' WHERE source = ?'; 

Save the changes you made and then edit the file functions.php, These are the lines I changed

/usr/share/squirrelmail/plugins/mail_alias/functions.php
$sql_data = array($username); 

/usr/share/squirrelmail/plugins/mail_alias/functions.php
//    $select_result1 = $dbConn->query($sql_add_alias_user, $data1); 

/usr/share/squirrelmail/plugins/mail_alias/functions.php
//    if (DB::isError($select_result1) || $dispErr) { 
//        echo '<p align=center><b>' . _("Error - Could not insert the alias record into th$ 
//           . '&nbsp;&nbsp;' . _("Please contact the system administrator.") . '</b></p>'; 
//      if (DB::isError($select_result1)) 
//          $rollback = 1; 
//    } 

/usr/share/squirrelmail/plugins/mail_alias/functions.php
//    $select_result1 = $dbConn->query($sql_del_alias_user, $emlalias); 

/usr/share/squirrelmail/plugins/mail_alias/functions.php
//    if (DB::isError($select_result1) || $dispErr) { 
//        echo '<p align=center><b>' . _("Error - Could not delete the alias record from th$ 
//           . '&nbsp;&nbsp;' . _("Please contact the system administrator.") . '</b></p>'; 
//      if (DB::isError($select_result1)) 
//          $rollback = 1; 
//    } 

Save the changes you made and then run

Code:
sudo squirrelmail-configure 

Then navigate you way to the plugin selection screen. 8 Plugins. Find mail_alias on the list of available plugins and enter the number. It should change to the top of the sceen under Installed plugins. Load up Squirrelmail goto the options link and follow the link to Mail Alias.

Remove the software you unzipped into /tmp.

5.13.2.4. Using MySQL to store Addresses

In the past you may have set up a pre-cleanup service. And perhaps the AMaVis documentation still tells you to set up such a service. This is deprecated.

Finally run a postfix reload and postfix check to make sure you have still no errors in your Postfix configuration. All incoming emails should now be tested for viruses and spam. Look at your /var/log/mail.log file for details. A great service for checking AMaViS is provided by webmail.us. They are sending you harmless test mails with the EICAR virus test signature. How does the content filtering work?

Let me explain how Postfix and AMaViS work together. Postfix receives your email and sends it to AMaViS as defined by your content_filter. As the no_address_mappings option is set during this first stage, aliases are ignored. AMaViS will then use the configured virus scanner to scan all attachments and spamassassin to check the email for certain spam criteria. If the attachments are archives (like .zip or .tar.gz) it will use the archive tools to unpack them. After scanning the email it will be sent back to Postfix on localhost's port 10025. But this time it sets the content_filter option to nothing thus bypassing further content scanning. And it clears the no_address_mappings option so aliases are now applied. If you would not disable the aliases during the first stage the aliases were applied twice which leads to getting emails twice. So we generally ignore the aliases at first and only use the aliases in the Postfix service that gets the emails back from AMaViS.

You can see these two steps in your /var/log/mail.log file. First you will notice a "relay=amavis" and then a "relay=virtual". If everything worked you will see a line like this in the /var/log/mail.log:

amavis[677]: (00677-02) Passed, <my@test.address> -> <user@virtual.test>, ... Message-ID: <20040716231708.8717C1C21E@myserver>, Hits: -

If you catch viruses (see eicar.org for a harmless test signature) you will see lines like this in the /var/log/mail.log:

amavis[11843]: (11843-01) INFECTED (Eicar-Test-Signature), <user@domain1> -> <user@domain2>...

Train it with ham and spam

To make AMaViS even more effective you should tell it what you think is spam. Since SpamAssassin is used for the bayesian filtering (it applies probabilities to every word to find out if the email is likely to be spam) it needs some training. You need to show it a large amount (more than a few hundred) mails of both categories. You cannot just show it spam mails and expect it to work.

Just a note: I know that it's possible to store these settings individually for each virtual user. Honestly I have not yet tried that since I found the documentation of AMaViS a bit confusing. Contributions on storing the learned information in the database per-user are welcome.

The tricky part is that you need sufficient access permissions to read the users' emails while at the same time storing the learned information in the home directory of the 'amavis' user. The permissions only allow the user 'vmail' to access emails. The group (g) and others (o) do not have any permissions. So I decided to run the learning task as 'root' from cron.

Just create a batch script that reads certain folders consisting of spam emails and have it called by crontab ('crontab -e' as root). I have hacked a script together and put it at /usr/local/bin/spamlearner:

SADIR=/var/lib/amavis/.spamassassin DBPATH=/var/lib/amavis/.spamassassin/bayes SPAMFOLDERS="\ /home/vmail/well-known-customer.com/fred/.spam/cur \ /home/vmail/spamtrap.org/jeanne/.spam/cur \ " HAMFOLDERS="\ /home/vmail/spamtrap.org/jeanne/.trash/cur \ "

for spamfolder in $SPAMFOLDERS ; do \ echo Learning spam from $spamfolder ; \ nice sa-learn --spam --showdots --dbpath $DBPATH $spamfolder done

for hamfolder in $HAMFOLDERS ; do \ echo Learning ham from $hamfolder ; \ nice sa-learn --ham --showdots --dbpath $DBPATH $hamfolder done

chown -R amavis:amavis $SADIR

You can see what AMaViS has recorded into its database by running sa-learn --dbpath /var/lib/amavis/.spamassassin/bayes --dump magic .

A note: this way you are training AMaViS' global bayesian database. So it applies to all emails that enter your system. Make sure you don't learn spam mails from unreliable or untrusted users. They can ruin your spam detection ratio by putting messages in their 'spam' folder that are not really spam. Just because a user never wants to get email from his ex-girlfriend again does not make it spam for everybody. So be careful about the mails you feed to the global bayes database.

Another note: Do not make SpamAssassin learn emails that users just 'forwarded' to you. The header information would be gone which contains much of the information that helps SpamAssassin recognise spam. Make sure they use the 'bounce' feature. Your best choice is to take the email messages directly from the user's maildir directory. Offering webmail access (optional)

Now that you know how your users can get and send their emails via POP3, IMAP and SMTP you may wonder if there is a comfy way to give your users access to their mailbox using webmail. Luckily this is easy. The package you need is called "squirrelmail" - a web mail system that can use any IMAP server - just like the Courier IMAP server we use here. Install it using apt-get install squirrelmail. To set it up you first need to add its configuration to your Apache configuration:

ln -s /etc/squirrelmail/apache.conf /etc/apache2/conf.d/squirrelmail.conf

Then run squirrelmail-configure to configure the basic settings. The default settings should suffice for a test. You can reconfigure it later at any point if you like.

Now access your web server like http://hostname/squirrelmail and you should get a login dialog. As usual use the email address as the username and the appropriate password from the `users` table. Squirrelmail will then contact the IMAP server on 'localhost' and show your emails. Mailing lists with mailman

A frequently asked question is how to run mailing lists with virtual domains using the famous 'mailman' software. Actually this is not very hard. There are three ways to accomplish that. Forwarding to local pipes

This first approach will use the aliases that you usually insert into /etc/aliases. You just have to understand that virtual users cannot have piped aliases. Piped... what? Well, once you have created a mailing list with the newlist command you are requested to add certain aliases to your /etc/aliases file like chitchat-admin, chitchat-bounces, chitchat-join and so on that point to destinations that look like "|/var/lib/mailman/mail/mailman post powerdns-debian". This means that the email is piped into the mailman program. Mailman is called and gets the email as input.

This works well for local domains but will fail if you put a piped alias like this into a virtual alias. That is because you do not have a system user whose user-id you could use to run this pipe. So you will have to make a circuit and forward your virtual email address to a local email address where you can use piped aliases.

I recommend that you use 'localhost' as your local domain (mydestination = localhost) and forward each of the mailman aliases to the @localhost equivalent. So if you have a chitchat-subscribe@virtual.domain address you just forward it to chitchat-subscribe@localhost and use the /etc/aliases as suggested by 'mailman'. Perhaps someone comes up with a nifty solution to put the /etc/aliases into the MySQL database, too. Let me know if you have invented something. Generic approach using regular expressions

There is a simple way to use mailman-based mailing lists when you are ready to sacrifice a hostname for mailinglists. Assume your domain is domain.com. You would then use lists.domain.com as the dedicated server name for mailing lists. Please see: http://listes.rezo.net/how.php. Using mailman as a transport service

The third way to use mailman is to create a transport (one of those services in /etc/postfix/master.cf for mailman. Please see the file /etc/mailman/postfix-to-mailman.py and read the INSTALLATION section of it. Troubleshooting Error messages Log file Error message Meaning /var/log/mail.log postfix/smtpd[11960]: NOQUEUE: reject: RCPT from myserver[10.20.30.40]: 550 <nonexisting@virtual.test>: Recipient address rejected: User unknown in virtual mailbox table; from=<user@domain> to=<nonexisting@virtual.test> ...to=<user2@my.testdomain>, relay=none, delay=0, status=bounced (unknown user: "user2@my.testdomain") Postfix knows that my.testdomain is a virtual domain. But the user account "user2@my.testdomain" was not found in the 'users' table. /var/log/mail.log ...warning: connect to mysql server mailtest: Access denied for user: 'service@myserver' (Using password: YES) Postfix tried to read from the MySQL database using the user service@myserver. However the combination of username and password have been rejected by MySQL. /var/log/mail.log ...warning: connect to mysql server mailtest: Access denied for user 'provider_admin'@'localhost.localdomain' (using password: YES) You seem to have an entry localhost.localdomain in your /etc/hosts file. Remove it. (Note: this has been discussed on the debian-devel mailing list. It was said that localhost.localdomain is correct. So you can as well grant MySQL privileges on localhost.localdomain instead of localhost. MySQL 5.0 will understand that these two host entries are identical.) /var/log/mail.log Clam Antivirus-clamd FAILED - unknown status: /var/lib/amavis/amavis-20050925T193330-15533/parts: Access denied. ERROR You need to add the user clamav to the group amavis if you want to use the clamd (ClamAV daemon). Use this command: adduser clamav amavis Output from postfix check postfix/postfix-script: warning: /var/spool/postfix/etc/hosts and /etc/hosts differ A file in the chroot jail in /var/spool/postfix/etc differs from the files in /etc. Just restart the postfix service and these files will be copied into the jail. MySQL debugging

In some cases it may happen that Postfix cannot even read from the MySQL database. If you suspect this you may want to take a look at the /var/log/mysql/mysql.log file. It contains all SQL queries to the database. Getting help on IRC

A lot of smart users can be found on the IRC channels #postfix and #postfix-de (German speaking) in the freenode.net network. You are invited to join us. I usually attend there as "Signum". Please do not message me privately. Just join the channel and ask your question as precisely as possible. And though I am flattered that so many people use my tutorial I cannot guarantee any reaction times if you send me an email. Migrating from the previous version of the tutorial

If you have already used an earlier version of this tutorial and want to adopt the changes then move your mail directories so that /home/vmail/user@domain becomes /home/vmail/domain/user. There are scripts that help you with this task on the contributions page . Server-side mail filtering using maildrop

A frequently asked question from our readers deals with server-side filtering. Many mail services offer to automatically sort spam emails into a seperate mail folder. You may even be used to 'procmail' which is a handy mail filter for local accounts on a system. Unfortunately it cannot work with virtual mailboxes. Most administrators appear to use 'maildrop' for this purpose. 'maildrop' is part of the Courier mail server and a Debian package exists already. It will not work as expected though because the 'maildrop' version in Debian/Sarge does not have MySQL support compiled in. As 'maildrop' would replace Postfix' built-in 'virtual' delivery agent it needed to know about the location of the virtual users' mailboxes. And it needed to do MySQL lookups for that purpose. If you really need this feature then consider reading Jasper Slits' page on this topic. He gives instructions on how to compile a 'maildrop' binary that is MySQL-enabled. It will also help you configure mail quotas.

My personal opinion on 'maildrop' is: forget about it if you can. It's nearly impossible to debug and more a dirty hack than a reasonable delivery agent. You may see warnings in your logs that are internally a 'segmentation fault' of the program itself that has just been hidden from you. Unfortunately there aren't any other delivery agents as far as I know.

If you are still happy with 'maildrop' then you are probably happy to hear that the next stable Debian release - Codename 'Etch' - will contain the new version of 'maildrop' that is using Courier's 'authlib' authentication library. You won't need to compile anything then. Thanks

A lot of people have mailed me for suggestions. I would like to thank the following people for providing valuable additions to this tutorial.

Greetings to the fine people on #postfix at freenode.net and of course thanks to my wife who showed a lot of patience with me. If you would like to translate this document please contact me. This document is available in Docbook-XML format for translators. Planned for the Etch tutorial

Contributions from readers

A lot of users have sent feedback that constantly helped improving this document. Some even sent us complete scripts of links to further documentation and software. Since that section is changing a lot please look at the contributions page for more information.

Also thanks to all readers who sent feedback on the tutorial - both technical and emotional. Perhaps you are curious to read what others think. Last change: Thursday, 12-Jul-2007 20:32:24 CEST / 423042 hits since 22.12.2003

There should be a blue line here

6. Testing Postfix

6.1. Basic Postfix Testing

Add a test user to mail1, it makes thing a little simpler for the testing. the user can be deleted when we are all setup. I'm going to use mailtest as the test user. I bet you saw that one coming .

Code:
sudo useradd -m -s /bin/bash mailtest 
sudo passwd mailtest 

To test your really basic installation we can use telnet connecting to 25 the default port for email.

Code:
telnet localhost 25 

Postfix will prompt you with something like the following and then we can use some SMTP commands to send our first email. (Remember to save it, it was our very first email!)

Code:
Trying 127.0.0.1... 
Connected to localhost. 
Escape character is '^]'. 
220 mail1.example.local ESMTP Postfix (Ubuntu) 

Type the following code segment at the prompt. A couple of things to note before hand as they may catch you out.

Code:
ehlo localhost 
mail from: root@localhost 
rcpt to: mailtest@localhost 
data 
Subject: My first mail on Postfix 
                  #  <<====== Just press return here 
Hi, 
Are you there? This mail was delivered via Postfix! 
regards, 
Your Admin 
. 
quit 

Whaho! our first email was sent to mailtest! Check the mailbox of mailtest to make sure it arrived okay. This is a little wield

Code:
su - mailtest 
mail 

When you type the mail command you will see something like the following output displayed in your terminal.

Code:
Mail version 8.1.2 01/15/2001.  Type ? for help. 
"/var/mail/mailtest": 1 message 1 new 
>N  1 root@localhost     Wed Jun  4 20:02   18/586   My first mail on Postfix 
& 

You will see that the emails are numbered. To view an email type its number from the queue. For example type no "1" to read the first mail (It is the only mail in our test). The type "d" to delete it and "q" to quit the mail program. The emails are written to a file called mbox in user's home directory.

All messages in an mbox type of mailbox are concatenated and stored in a single file. This can cause locking problems when a lot of emails arrive at the same time.

6.2. Testing Maildir Format Mail.

You can send some emails using the process above Jump to Testing your Setup. Once you have sent the email take a look the Maildir in the home directory of mailtest. Have a look in all three of the subdirectories.

6.3. Testing POP and IMAP

6.3.1. Viewing Your Mail With POP

Send another email using the procedure above, or as we installed mailx which is a simpler method from the command line we could use:

Code:
echo -e "This is an email sent with mailx\nIt can be done all on one line\nregards\nAdmin." | mail -s "This will be the subject" mailtest 

and then to actually see your emails as you would if you used a pop3 email client follow the next bit through.

Code:
telnet mail1 110 

Use the following example code segment for your test.

Code:
Trying 192.168.0.10... 
Connected to mail1.example.local. 
Escape character is '^]'. 
+OK Hello there. 

Type the following code segment in the prompt provided by the Courier POP3 server.

Code:
user mailtest 
+OK Password required. 
pass <password> 
+OK logged in. 
list                # <<== list all your emails 
top 1 10            # <<== views the top 10 lines of message 1 
dele 1              # <<== deletes message 1 
quit 

6.3.2. Viewing your Mail with IMAP

Type in a terminal:

Code:
telnet mail1 143 

Use the following example code segment for your test with IMAP.

Code:
Trying 192.168.0.10... 
Connected to mail1.example.local. 
Escape character is '^]'. 
* OK [CAPABILITY IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT THREAD=REFERENCES SORT 
QUOTA IDLE ACL ACL2=UNION] Courier-IMAP ready. Copyright 1998-2005 Double Precision, Inc.  See COP 
YING for distribution information. 

You can now read your emails with combinations of the following commands. Have some fun, go play around.

Code:
1 LOGIN mailtest <password> 
1 LIST "" "*" 
1 EXAMINE INBOX 
1 SELECT INBOX 
1 FETCH 1 all 
1 FETCH 1 body 
1 CLOSE 
1 LOGOUT 

A good example of How to verify basic IMAP connectivity by using Telnet. Go take a look.

6.4. Using A Full Email Client

At this point we can actually send and receive email with full email clients such as Thunderbird and Evolution.

6.4.1. Setting up Thunderbird.

To add your new server from the Main menu, Edit->Account Settings->Add Account. This brings up a setup wizard.

There should be a blue line here

A. Turn Off Debug Logging.

While we were setting up the sytem and getting things working we turned on a lot of extra logging. You do remember where it all it don't you?

File name Look for Action
/etc/mysql/my.cnf log = /var/log/mysql/mysql.log Comment out with #
/etc/courier/authdaemonrc DEBUG_LOGIN=2 Change to 0
/etc/postfix/sasl/smtpd.conf log_level: Comment out with #
/etc/postfix/main.cf smtpd_tls_loglevel Comment out with #
  notify_classes Comment out for default resource, software
There should be a blue line here

B. Further Information.

B.1. Links I Found Useful

Ubuntu official docs

Getting VMware installed and Configured

Postfix Documentation.

Posfix Basic Setup

Amavis Documentition.

Clamav

Wordpress