Networking

Hardware

Software

Consultation

 

POP3 & IMAP Server Installation

 
 
with SQL Authentication, Using Postfix, Dovecot & MySQL

This tutorial shows an installation of Dovecot & Postfix with MySQL authentication.  The emails and domains are all virtual and are configured authenticating to a MySQL backend.  It also allows multiple emails and multiple domains to all be the same virtual user. ie: me@mydomain, you@mydomain, me@someotherdomain can all be accessed via the same account (or any of the accounts, if you'd like). The installation will include the packages required for both IMAP and POP3 connections, but the POP3 will not be enabled in the configuration...

Conventions
Commands - White on Black text is meant for copying and pasting.
Output - Yellow on Black text is the common output from a
      command.
Alternate Prompt - Red on Black text is an alternate input
      prompt, not meant for copying, but indicating it
      should be there before continuing.
Requirements

The tutorial requires a Linux installation with at least one static interface connected to the Internet, we will be using Ubuntu Server AMD64. The SMTP server, Postfix, will require a connection to the Internet to be useful, this does not mean that the server is required to be a gateway, but needs to be on an open connection to the Internet; However, the process is simplified if it is on the gateway machine.


Initial Package Installation

Depending on your distribution there may be an option to install Dovecot and Postfix as single a package, which includes Ubuntu's configuration files for Dovecot and Postfix interoperability and all necessary packages. Start by logging into your installation as root, then issue the command:

aptitude search dovecot-postfix
p	dovecot-postfix		- full mail server stack provided by Ubuntu server team

If there is a single package you can install it:

aptitude -y install dovecot-postfix

Also, you could search for the required packages:

aptitude search dovecot
p	dovecot-common      - secure mail server that supports mbox and maildir mailboxes
p	dovecot-dev         - header files for the dovecot mail server
p	dovecot-imapd       - secure IMAP server that supports mbox and maildir mailboxes
p	dovecot-pop3d       - secure POP3 server that supports mbox and maildir mailboxes
p	dovecot-postfix     - full mail server stack provided by Ubuntu server team

aptitude search postfix
p	bld-postfix         - Postfix tools for the Black List Daemon
p	dovecot-postfix     - full mail server stack provided by Ubuntu server team
p	dtc-postfix-courier - web control panel for admin and accounting hosting services (more depends)
p	gforge-mta-postfix  - collaborative development tool - mail tools (using Postfix)
p	postfix             - High-performance mail transport agent
p	postfix-cdb         - CDB map support for Postfix
p	postfix-dev         - Loadable modules development environment for Postfix
p	postfix-doc         - Documentation for Postfix
p	postfix-gld         - greylisting daemon for postfix, written in C, uses MySQL
p	postfix-ldap        - LDAP map support for Postfix
p	postfix-mysql       - MySQL map support for Postfix
p	postfix-pcre        - PCRE map support for Postfix
p	postfix-pgsql       - PostgreSQL map support for Postfix
p	postfix-policyd     - anti-spam plugin for Postfix
p	postfix-policyd-spf-perl	- pure-Perl Postfix policy server for RFC 4408 SPF checking
p	postfix-policyd-spf-python	- pure-Python Postfix policy daemon for SPF checking
v	postfix-tls         -

At this point we could install the dovecot-postfix package, or we could simply install the packages ourselves:

aptitude -y install dovecot-common dovecot-imapd dovecot-pop3d postfix postfix-mysql

This would give us a IMAP, POP3 and a SMTP Server.  You will be asked several questions regarding how you would like Postfix configured, use the defaults.

Document Packages

Installing document packages is always recommended, as they will have the most version specific content. In this case only Postfix has one, postfix-doc...


MySQL Setup

For the purpose of this tutorial, we will assume that you do not have a MySQL server installed. As we will authenticate using a mysql database, we need to install the mysql server, using the command:

aptitude install mysql-server

The default root password for MySQL is likely empty. You might want to change it by typing (PLEASE, use a different password.):

mysqladmin -u root password 'hereismypassword'

I like to create the database using a sql file, there is no proper directory for this, so your home directory will do as well as any other:

Start by moving to your home directory, then (using your favorite editor) create a file called maildb_create.sql:

cd ~
vim maildb_create.sql

Then place the following itno it:

CREATE DATABASE mailusers_db;
 
GRANT USAGE ON *.* TO maild_user@localhost IDENTIFIED BY 'maild_password';
 
GRANT SELECT, INSERT, UPDATE, DELETE ON mailusers_db.* TO 'maild_user'@'localhost';
 
USE mailusers_db;
 
CREATE TABLE `users` (
  `userid` varchar(128) NOT NULL,
  `domain` varchar(128) NOT NULL,
  `password` varchar(64) default NULL,
  `home` varchar(255) NOT NULL,
  `uid` int(11) unsigned NOT NULL default '1000',
  `gid` int(11) unsigned NOT NULL default '1000',
  `Active` char(1) NOT NULL default 'Y',
  PRIMARY KEY  (`userid`,`domain`)
) COMMENT='Mail Server Virtual Users table';
 

Save it and type:

mysql -u root -p  < maildb_create.sql

Now, we are going to create our first virtual mail user. In order to create our first user and password, we are going to connect using the database user access we have just created:

mysql -u maild_user -p mailusers_db

Again, the password is 'maild_password' (without the quotes).

Create your first user:

mysql> INSERT INTO `users` (`userid`, `domain`, `password`, `home`, `uid`, `gid`, `Active`) VALUES ('postmaster', 'example.com', '{PLAIN}userpassword', '/home/vmail/postmaster', 1000, 1000, 'Y');

There are a few things we haven't covered yet, so I'll gleen over them and hopefully by the end they will make sence.

Everybody needs a postmaster, right?? Please replace example.com with your own domain. If you don't have one yet, well get one, then use it...

Also, please replace 'userpassword' with the password for your postmaster, and yes the '{PLAIN}' is required for this to work.

There is currently no vmail user or group, but we will be making one, and all emails will be handled by that user, who will have a home directory of /home/vmail, a uid of 1000 and gid of 1000.

That should about do it for the MySQL server, if you'd like to add more users follow the same form:

mysql> INSERT INTO `users` (`userid`, `domain`, `password`, `home`, `uid`, `gid`, `Active`) VALUES ('<UserName>', '<Domain Name>', '{PLAIN}<Users Password>', '/home/vmail/<Users mail Directory>', 1000, 1000, 'Y');

To create an alias type account, simply leave the password field empty, and use an existing home directory, like so:

mysql> INSERT INTO `users` (`userid`, `domain`, `password`, `home`, `uid`, `gid`, `Active`) VALUES ('postmaster_alias', 'example.com', '', '/home/vmail/postmaster', 1000, 1000, 'Y');

This will place all mail to postmaster_alias@example.com in postmaster@example.com's mailbox, and will not allow postmaster_alias@example.com to log in.


Dovecot Setup

Move to the Dovecot configuration directory:

cd /etc/dovecot

Create a sub directory

mkdir config.backups

Move all the files into the directory you just created. Do not move dovecot-sql.conf as we will require it later.

mv dovecot.conf config.backups/
mv dovecot.conf.bak config.backups/
mv dovecot-db-example.conf config.backups/
mv dovecot-ldap.conf config.backups/
mv dovecot-postfix.conf config.backups/

Create a new dovecot.conf file:

vim dovecot.conf

Fill it with the following:

# Remove pop3 things if you don't want them
#protocols = imap imaps pop3 pop3s
protocols = imap imaps managesieve

protocol managesieve {
	mail_debug=yes
	sieve=/home/vmail/%u/.dovecot.sieve
	sieve_storage=/home/vmail/%u/sieve
}

# It's nice to have separate log files for Dovecot. You could do this
# by changing syslog configuration also, but this is easier.
log_path = /var/log/dovecot.log
info_log_path = /var/log/dovecot-info.log

ssl_disable = no

# The following is required to allow plain text logins
disable_plaintext_auth = no

# PEM encoded X.509 SSL/TLS certificate and private key. They're opened before
# dropping root privileges, so keep the key file unreadable by anyone but
# root.
# Preferred permissions: root:root 0444
ssl_cert_file = /etc/ssl/certs/ssl-mail.pem
# Preferred permissions: root:root 0400
ssl_key_file = /etc/ssl/private/ssl-mail.key

# SSL ciphers to use
ssl_cipher_list = ALL:!LOW:!SSLv2:ALL:!aNULL:!ADH:!eNULL:!EXP:RC4+RSA:+HIGH:+MEDIUM

# We're using Maildir format
mail_location = maildir:~/Maildir

# If you're using POP3, you'll need this:
pop3_uidl_format = %08Xu%08Xv

# Optimizations:
dotlock_use_excl=yes
maildir_copy_with_hardlinks=yes

# Authentication configuration:
auth_verbose = yes

protocol lda {
	# Address to use when sending rejection mails.
	postmaster_address = postmaster

	mail_plugins = cmusieve

	# If user is over quota, return with temporary failure instead of
	# bouncing the mail.
	quota_full_tempfail = yes

	# Format to use for logging mail deliveries. You can use variables:
	#  %$ - Delivery status message (e.g. "saved to INBOX")
	#  %m - Message-ID
	#  %s - Subject
	#  %f - From address
	deliver_log_format = msgid=%m: %$
	
	# Human readable error message for rejection mails. You can use variables:
	#  %n = CRLF, %r = reason, %s = original subject, %t = recipient
	rejection_reason = Your message to <%t> was automatically rejected:%n%r
	
	# UNIX socket path to master authentication server to find users.
	auth_socket_path = /var/run/dovecot/auth-master
}

auth_debug = yes
auth_debug_passwords = yes

auth default {
	mechanisms = plain login

	# The following is for a flat file auth system
	#--%<--------------------------------------------------#
#	passdb passwd-file {
#		args = /etc/dovecot/passwd
#	}
#	userdb passwd-file {
#		args = /etc/dovecot/passwd
#	}
	#--%<--------------------------------------------------#
	
	# This will allow us to authenticate using mysql backend
	#--%<--------------------------------------------------#
	passdb sql {
		args = /etc/dovecot/dovecot-sql.conf
	}
	userdb prefetch {
	}
	# The userdb below is used only by deliver.
		userdb sql {
		args = /etc/dovecot/dovecot-sql.conf
	}
	#--%<---------------------------------------------------#
	
	socket listen {
		master {
			path = /var/run/dovecot/auth-master
			mode = 0660
			user = vmail
			group = vmail
		}
		client {
			# The client socket is generally safe to export to everyone. Typical use
			# is to export it to your SMTP server so it can do SMTP AUTH lookups
			# using it.
			path = /var/spool/postfix/private/dovecot-auth
			mode = 0660
			user = postfix
			group = postfix
		}
	}
}


In the above file we referenced, /etc/ssl/certs/ssl-mail.pem as the ssl_cert_file and /etc/ssl/private/ssl-mail.key as the ssl_key_file. We need to make sure that the files exists and are valid. We will create symbolic links to /etc/ssl/certs/ssl-cert-snakeoil.pem and /etc/ssl/private/ssl-cert-snakeoil.key:

cd /etc/ssl/private
ln -s ssl-cert-snakeoil.key ssl-mail.key
cd /etc/ssl/certs
ln -s ssl-cert-snakeoil.pem ssl-mail.pem

This will ensure that you don not receive a ssl_cert_file error.


All email will be delivered using the same user and group. The configuration file above has the user as vmail and the group as vmail as well. The user and group could be anything, just be sure to change the configuration file to match. In order to use the vmail user and group they need to be created:

useradd -m -s /bin/false -u 1000 vmail
rm /home/vmail/.??*

This will create a non-system user with an UID and GIU of 1000, it also creates a directory in /home called vmail with .bash_logout, .bashrc and .profile, which we have removed.

If the UID or GID of 1000 is missing substitute another number for all of the commands, 2000 for example. It just has to be over 999.

The next thing we need to do is setup Dovecot to talk to MySQL, this is done with a the dovecot-sql.conf file. In the dovecot directory open dovecot-sql.conf with your favorite editor:

vim dovecot-sql.conf

and ensure that it has the following configuration:

# This file is opened as root, so it should be owned by root and mode 0600.
#
# http://wiki.dovecot.org/AuthDatabase/SQL
#
# For the sql passdb module, you'll need a database with a table that
# contains fields for at least the username and password. If you want to
# use the user@domain syntax, you might want to have a separate domain
# field as well.
#
# If your users all have the same uig/gid, and have predictable home
# directories, you can use the static userdb module to generate the home
# dir based on the username and domain. In this case, you won't need fields
# for home, uid, or gid in the database.
#
# If you prefer to use the sql userdb module, you'll want to add fields
# for home, uid, and gid. Here is an example table:
#
# CREATE TABLE users (
#     username VARCHAR(128) NOT NULL,
#     domain VARCHAR(128) NOT NULL,
#     password VARCHAR(64) NOT NULL,
#     home VARCHAR(255) NOT NULL,
#     uid INTEGER NOT NULL,
#     gid INTEGER NOT NULL,
#     active CHAR(1) DEFAULT 'Y' NOT NULL
# );

# Database driver: mysql, pgsql, sqlite
#driver =
driver = mysql

# Database connection string. This is driver-specific setting.
#
# pgsql:
#   For available options, see the PostgreSQL documention for the
#   PQconnectdb function of libpq.
#
# mysql:
#   Basic options emulate PostgreSQL option names:
#     host, port, user, password, dbname
#
#   But also adds some new settings:
#     client_flags        - See MySQL manual
#     ssl_ca, ssl_ca_path - Set either one or both to enable SSL
#     ssl_cert, ssl_key   - For sending client-side certificates to server
#     ssl_cipher          - Set minimum allowed cipher security (default: HIGH)
#     option_file         - Read options from the given file instead of
#                           the default my.cnf location
#     option_group        - Read options from the given group (default: client)
#
#   You can connect to UNIX sockets by using host: host=/var/run/mysqld/mysqld.sock
#   Note that currently you can't use spaces in parameters.
#
#   MySQL supports multiple host parameters for load balancing / HA.
#
# sqlite:
#   The path to the database file.
#
# Examples:
#   connect = host=192.168.1.1 dbname=users
#   connect = host=sql.example.com dbname=virtual user=virtual password=blarg
#   connect = /etc/dovecot/authdb.sqlite
#
#connect =
connect = host=localhost dbname=mailusers_db user=maild_user password=maild_password

# Default password scheme.
#
# List of supported schemes is in
# http://wiki.dovecot.org/Authentication/PasswordSchemes
#
#default_pass_scheme = PLAIN-MD5

# passdb query to retrieve the password. It can return fields:
#   password - The user's password. This field must be returned.
#   user - user@domain from the database. Needed with case-insensitive lookups.
#   username and domain - An alternative way to represent the "user" field.
#
# The "user" field is often necessary with case-insensitive lookups to avoid
# e.g. "name" and "nAme" logins creating two different mail directories. If
# your user and domain names are in separate fields, you can return "username"
# and "domain" fields instead of "user".
#
# The query can also return other fields which have a special meaning, see
# http://wiki.dovecot.org/PasswordDatabase/ExtraFields
#
# Commonly used available substitutions (see http://wiki.dovecot.org/Variables
# for full list):
#   %u = entire user@domain
#   %n = user part of user@domain
#   %d = domain part of user@domain
#
# Note that these can be used only as input to SQL query. If the query outputs
# any of these substitutions, they're not touched. Otherwise it would be
# difficult to have eg. usernames containing '%' characters.
#
# Example:
#   password_query = SELECT userid AS user, pw AS password \
#     FROM users WHERE userid = '%u' AND active = 'Y'
#
#password_query = \
#  SELECT username, domain, password \
#  FROM users WHERE username = '%n' AND domain = '%d'

# userdb query to retrieve the user information. It can return fields:
#   uid - System UID (overrides mail_uid setting)
#   gid - System GID (overrides mail_gid setting)
#   home - Home directory
#   mail - Mail location (overrides mail_location setting)
#
# None of these are strictly required. If you use a single UID and GID, and
# home or mail directory fits to a template string, you could use userdb static
# instead. For a list of all fields that can be returned, see
# http://wiki.dovecot.org/UserDatabase/ExtraFields
#
# Examples:
#   user_query = SELECT home, uid, gid FROM users WHERE userid = '%u'
#   user_query = SELECT dir AS home, user AS uid, group AS gid FROM users where userid = '%u'
#   user_query = SELECT home, 501 AS uid, 501 AS gid FROM users WHERE userid = '%u'
#
#user_query = \
#  SELECT home, uid, gid \
#  FROM users WHERE username = '%n' AND domain = '%d'

# If you wish to avoid two SQL lookups (passdb + userdb), you can use
# userdb prefetch instead of userdb sql in dovecot.conf. In that case you'll
# also have to return userdb fields in password_query prefixed with "userdb_"
# string. For example:
#password_query = \
#  SELECT userid AS user, password, \
#    home AS userdb_home, uid AS userdb_uid, gid AS userdb_gid \
#  FROM users WHERE userid = '%u'

######################################################################################
##      This is added from the prefetch examples                                                                                ##
######################################################################################

#password_query = SELECT userid AS user, password, home AS userdb_home, uid AS userdb_uid, gid AS userdb_gid FROM users WHERE userid = '%u' AND Active = 'Y'
password_query = SELECT concat_ws("@",userid,domain) AS user, password, home AS userdb_home, uid AS userdb_uid, gid AS userdb_gid FROM users WHERE userid = '%n' AND domain = '%d' AND Active = 'Y'
user_query = SELECT home, uid, gid FROM users WHERE userid = '%n' AND domain = '%d' AND Active = 'Y'

######################################################################################

As you can see the important parts are 'driver', 'connect', 'password_query', & 'user_query'. As we have already setup the database and have a user, we are good to go... For Dovecot anyway. but we should check just to make sure.

 

Flat File Authentication

The following section describes a flat file authentication system, it has been replaced with MySQL authentication, but is still interesting:

The system will run but as there are no emails accounts or domains it isn't good for very much.  In order to simplify administration of the server, we are going to use a single flat file for users names and passwords, called passwd.  The name of the file and it's location are set in the dovecot.conf file and can be whatever you'd like.  The format of the file is essentially the same as that of the normal unix passwd file:

[User Name]:{[Password Type]}[Password]:[Local User]:[Local Group]:[User Info]:[Directory Used]:[Shell]

Obviously some of the properties are not going to be used (User Info, and Shell).  A normal plain text entry would look like this:

me@mytestdomain.com:{PLAIN}mypassword:vmail:vmail::/home/vmail/me

This is the file that Dovecot will look at when receiving emails AND when a user logs in to get emails.  This leads to the ability to allow many email recipients to be delivered to one place and checked by one user, as in:

me@mytestdomain.com::vmail:vmail::/home/vmail/me
mealso@mytestdomain.com::vmail:vmail::/home/vmail/me
me:{PLAIN}mypassword:vmail:vmail::/home/vmail/me

This would allow emails to me@mytestdomain.com, mealso@mytestdomain.com and me to all be checked by 'me'.  Note that by removing any password info, you disable any login's by that user; therefore, me@mytestdomain.com and mealso@mytestdomain.com may NOT log in using the email client. Your final passwd file may look something like:

## Email Users ##
## [User Name]:{[Password Type]}[Password]:[Local User]:[Local Group]:[User Info]:[Directory Used]:[Shell] ##
root:{PLAIN}rootpassword:vmail:vmail::/home/vmail/root
user@mydomain:{PLAIN}userpassword:vmail:vmail::/home/vmail/user

There may be some concern with the use of plain text passwords; however, if you are on a small local network it shouldn't pose a problem, and the non-plaintext passwords would add to much to this tutorial.  There will be a tutorial added to deal with encrypted passwords to follow...

 

Adding Domains

If you would like to use more than one domain: mydomain.com , yourdomain.com, anotherdomain.com, etc... add them to the virtual_mailbox_domains parameter in Postfix or they will get bounced.


Dovecot will not start until you have created the log files:

touch /var/log/dovecot-info.log
touch /var/log/dovecot.log
chown vmail:vmail /var/log/dovecot*.log

The files must be owned by vmail or Postfix and Dovecot will not be able to write to them when email is delivered.  If you find that you are getting permission errors in your log files, try adding write permissions to the log files you've created.  The log files will become very large after a time if they are not kept in check; therefore, lets create a rule to rotate the log files:

vim /etc/logrotate.d/dovecot

Place the following within:

# dovecot SIGUSR1: Re-opens the log files.
	/var/log/dovecot*.log {
	missingok
	notifempty
	delaycompress
	sharedscripts
	postrotate
	/bin/kill -USR1 `cat /var/run/dovecot/master.pid 2>/dev/null` 2> /dev/null || true
	endscript
}

 

Test your Configuration

Restart Dovecot and check to see if you can log in:

/etc/init.d/dovecot restart

Open a terminal, not on the server, and try to log into the IMAP server:

telnet [Your IP Address or Domain Name] 143
Trying [Your IP Address or Domain Name]...
Connected to [Your IP Address or Domain Name].
Escape character is '^]'.
* OK Dovecot ready.
a login user pass
a OK Logged in.

Logging in means everything is working correctly.  Yes, you must type the 'a' in front of 'login user pass'.


With that, we are done with the Dovecot setup!!


Postfix Setup

Move to the Postfix configuration directory, and edit the master.cf file:

cd /etc/postfix
vim master.cf

Add the following to the end of the file:

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

This lets up pass the received emails to Dovecot Deliver, the indentation on the second line is important, do not remove it.

The main.cf file should be similar to:

#
# Postfix master process configuration file.  For details on the format
# of the file, see the master(5) manual page (command: "man 5 master").
#
# Do not forget to execute "postfix reload" after editing this file.
#
# ==========================================================================
# service	type		private	unpriv	chroot	wakeup	maxproc	command + args
#		(yes)	(yes)	(yes)	(never)	(100)
# ==========================================================================
smtp      inet  n       -       -       -       -       smtpd
#submission inet n       -       -       -       -       smtpd
#  -o smtpd_tls_security_level=encrypt
#  -o smtpd_sasl_auth_enable=yes
#  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
#  -o milter_macro_daemon_name=ORIGINATING
#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
#628      inet  n       -       -       -       -       qmqpd
pickup    fifo  n       -       -       60      1       pickup
cleanup   unix  n       -       -       -       0       cleanup
qmgr      fifo  n       -       n       300     1       qmgr
#qmgr     fifo  n       -       -       300     1       oqmgr
tlsmgr    unix  -       -       -       1000?   1       tlsmgr
rewrite   unix  -       -       -       -       -       trivial-rewrite
bounce    unix  -       -       -       -       0       bounce
defer     unix  -       -       -       -       0       bounce
trace     unix  -       -       -       -       0       bounce
verify    unix  -       -       -       -       1       verify
flush     unix  n       -       -       1000?   0       flush
proxymap  unix  -       -       n       -       -       proxymap
proxywrite unix -       -       n       -       1       proxymap
smtp      unix  -       -       -       -       -       smtp
# When relaying mail as backup MX, disable fallback_relay to avoid MX loops
relay     unix  -       -       -       -       -       smtp
        -o smtp_fallback_relay=
#       -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
showq     unix  n       -       -       -       -       showq
error     unix  -       -       -       -       -       error
retry     unix  -       -       -       -       -       error
discard   unix  -       -       -       -       -       discard
local     unix  -       n       n       -       -       local
virtual   unix  -       n       n       -       -       virtual
lmtp      unix  -       -       -       -       -       lmtp
anvil     unix  -       -       -       -       1       anvil
scache    unix  -       -       -       -       1       scache
#
# ====================================================================
# Interfaces to non-Postfix software. Be sure to examine the manual
# pages of the non-Postfix software to find out what options it wants.
#
# Many of the following services use the Postfix pipe(8) delivery
# agent.  See the pipe(8) man page for information about ${recipient}
# and other message envelope options.
# ====================================================================
#
# maildrop. See the Postfix MAILDROP_README file for details.
# Also specify in main.cf: maildrop_destination_recipient_limit=1
#
maildrop  unix  -       n       n       -       -       pipe
  flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
#
# See the Postfix UUCP_README file for configuration details.
#
uucp      unix  -       n       n       -       -       pipe
  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
#
# Other external delivery methods.
#
ifmail    unix  -       n       n       -       -       pipe
  flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
bsmtp     unix  -       n       n       -       -       pipe
  flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
scalemail-backend unix  -       n       n       -       2       pipe
  flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
mailman   unix  -       n       n       -       -       pipe
  flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
  ${nexthop} ${user}
##-------%<---------------------------------------------------------------------------##
dovecot unix - n n - - pipe
  flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -f ${sender} -d $(recipient)
##-------%<---------------------------------------------------------------------------##

The last few lines are the new ones.


We need to create a maps file that will allow Postfix to talk with MySQL. If you are not in the Postfix directory move to it and create a file mysql-virtual.cf:

vim mysql-virtual.cf

Place the following inside:

#
# mysql-virtual.cf - local recipients for mail server.
#
hosts = 127.0.0.1
user = maild_user
password = maild_password

dbname = mailusers_db
table = users

query = SELECT concat_ws("@",userid,domain) AS user FROM users WHERE userid = '%u' AND domain = '%d' AND Active = 'Y'

Save the file.

Next we edit the main.cf file. It is the primary configuration file for Postfix. There are several parameters that may require changing:

  • alias_database
    • DEFAULT: hash:/etc/aliases
    • REQUIRED: Use default.
    • NOTE: The "alias_database" parameter defines what text file will be converted to a database and what "database type" will be used for the conversion when running the "newaliases" command.
  • alias_maps
    • DEFAULT: hash:/etc/aliases, nis:mail.aliases
    • REQUIRED: hash:/etc/aliases
    • NOTE: The alias databases that are used for local delivery. This will still be used for local required addresses, root, postmaster, etc...
  • inet_interfaces
    • DEFAULT: all
    • REQUIRED: Use default.
    • NOTE: The network interface addresses that this mail system receives mail on. Specify "all" to receive mail on all network interfaces (default), and "loopback-only" to receive mail on loopback network interfaces only (Postfix version 2.2 and later). The parameter also controls delivery of mail to user@[ip.address].
  • home_mailbox
    • DEFAULT: None.  See postconf -d | grep home_mailbox
    • REQUIRED: Use default.
    • NOTE: Optional pathname of a mailbox file relative to a local user's home directory.
  • local_recipient_maps
    • DEFAULT: proxy:unix:passwd.byname $alias_maps
    • REQUIRED: Use default.
    • NOTE: By default, the Postfix SMTP server rejects mail for recipients not listed with the local_recipient_maps parameter. If you clear this parameter ALL recipients will be accepted; however if there is no user to deliver the message to, it will live in limbo forever.
  • mailbox_command
    • DEFAULT: None.  See postconf -d | grep mailbox_command
    • REQUIRED: Use default.
    • REQUIRED: Optional external command that the local delivery agent should use for mailbox delivery. The command is run with the user ID and the primary group ID privileges of the recipient. Exception: command delivery for root executes with $default_privs privileges. This is not a problem, because 1) mail for root should always be aliased to a real user and 2) don't log in as root, use "su" instead.
  • mailbox_transport
    • DEFAULT: None.  See postconf -d | grep mailbox_transport
    • REQUIRED:Use default.
    • NOTE: Optional message delivery transport that the local delivery agent should use for mailbox delivery to all local recipients, whether or not they are found in the UNIX passwd database. The precedence of local delivery features from high to low is: aliases, .forward files, mailbox_transport_maps, mailbox_transport, mailbox_command_maps, mailbox_command, home_mailbox, mail_spool_directory, fallback_transport_maps, fallback_transport and luser_relay.
  • mydestination
    • DEFAULT: $myhostname, localhost.$mydomain, localhost
    • REQUIRED: localhost
    • NOTE: You could setup your email server with two separate systems, local & virtual, then this field would take a list of domains that have local users. The list of domains that are delivered via the $local_transport mail delivery transport. By default this is the Postfix local delivery agent which looks up all recipients in /etc/passwd and /etc/aliases. The SMTP server validates recipient addresses with $local_recipient_maps and rejects non-existent recipients.
  • myhostname
    • DEFAULT: Local machines fully quallified domain name (FQDN).
    • REQUIRED: Use default.
    • NOTE: The internet hostname of this mail system. The default is to use the fully-qualified domain name (FQDN) from hostname, or to use the non-FQDN result from hostname and append ".$mydomain". $myhostname is used as a default value for many other configuration parameters.
  • mynetworks
    • DEFAULT: All interface subnets, internal, external and loopback
    • REQUIRED: Used default
    • NOTES: This may be configured...  Wrong...  Add a # to the front of the line, delete the line, or configure your required networks in (CIDR) notation: 192.168.1.1/24.
  • relayhost
    • DEFAULT: None.  See postconf -d | grep relayhost
    • REQUIRED: Some ISP's require that you use there SMTP server for outgoing mail, and block port 25; If this is the case, use there mail host here to get the desired effect.  Many ISP's will drop the port block when a static IP is used, which is normally required for email serving anyway.
  • virtual_mailbox_domains
    • DEFAULT: $virtual_mailbox_maps
    • REQUIRED: Any domain for which this computer is the email server.
    • NOTE: If the system has a FQDN then $mydomain will be set, by Postfix, to the domain portion of the FQDN, and $mydomain.
  • virtual_mailbox_maps
    • DEFAULT: None.
    • REQUIRED no MySQL: Use default
    • REQUIRED MySQL: mysql:/etc/postfix/mysql-virtual.cf
    • NOTE: Lookup tables with all valid addresses in the domains that match $virtual_mailbox_domains. This references the database we set up earlier, this will allow Postfix to Bounce unknown users at the SMTP stage, letting the sender know something went wrong.
  • virtual_transport
    • DEFAULT: None.
    • REQUIRED: dovecot
    • NOTE: This tells Postfix that for all virtual users, use the 'dovecot' transport that we created earlier in the master.cf file.

To use the default value you can preceed the line with a # (commenting it out) or you can remove the line, commenting the line out is the prefered method.  If the perameters do not exist within the configuration file, simply add them where ever you see fit.  OR, backup your current file and use the following (be sure t adjust the appropriate parameters).:

# Non-Postfix mailbox store:
#	separate domains,
#	non-UNIX accounts.

# Defaults to 'alias_maps = hash:/etc/aliases, nis:mail.aliases'
# and there is no NIS server.
alias_maps = hash:/etc/aliases

# Appending .domain is the Mail User Agent's job.
append_dot_mydomain = no

# Stop local addresses from getting @$myorigin appended to them.
append_at_myorigin = no

# No local users to notify, turn off biff.
biff = no

# Required for Dovecot/Postfix integration.
# Please see http://wiki.dovecot.org/LDA/Postfix
# 0 - means to limit.
mailbox_size_limit = 0

# 50 Megabyte messages MAX.
message_size_limit = 52428800

# No local users.
mydestination = localhost

# Defaults to 'myorigin = $myhostname'.
myorigin = /etc/mailname

# Required for many external programs.
recipient_delimiter = +

# The banner that is displayed.
smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)

# Force postfix to follow SMTP RFC.
smtpd_helo_required = yes

# Domains that postfix will accept mail.
virtual_mailbox_domains = [Virtual Domain 1], [Virtual Domain 2], [etc...]

# Map of Users for which postfix will accept mail.
virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual.cf

# After mail is accepted it's passed to the Local Delivery Agent.
virtual_transport = dovecot
dovecot_destination_recipient_limit = 1
## NOTE: You won't find dovecot_destination_recipient_limit in the Postfix documentation, instead see the documentation for transport_destination_recipient_limit

### START - SMTP Restrictions - START ###
smtpd_client_restrictions =
        permit_sasl_authenticated,
        permit_mynetworks,
        reject_unauth_pipelining,
        reject_unknown_client_hostname

smtpd_helo_restrictions =
        permit_sasl_authenticated,
        permit_mynetworks,
        reject_non_fqdn_helo_hostname,
        reject_unknown_helo_hostname,
        reject_invalid_helo_hostname,
        permit

smtpd_sender_restrictions =
        permit_sasl_authenticated,
        permit_mynetworks,
        reject_non_fqdn_sender,
        reject_unknown_sender_domain,
        permit

smtpd_recipient_restrictions =
        permit_sasl_authenticated,
        reject_non_fqdn_recipient,
        reject_unknown_recipient_domain,
        permit_mynetworks,
        reject_unauth_destination,
        reject_invalid_hostname,
        permit
### END - SMTP Restrictions - END ###

# SASL (Simple Authentication and Security Layer) parameters
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/dovecot-auth
smtpd_sasl_auth_enable = yes
broken_sasl_auth_clients = yes
smtpd_sasl_authenticated_header = yes

# TLS (Transport Layer Security) parameters
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_use_tls=yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for
# information on enabling SSL in the smtp client.

Client, Helo, Sender and Recipient Restrictions have been added to reduce SPAM, please have a look at them in the configuration above, they link to definitions on postfix.org

Testing Restrictions

If you would like to see the effect a restriction will have on email simple prefix warn_if_reject to the rule, as in warn_if_reject reject_non_fqdn_recipient, for example:

# Recipient Restriction #
smtpd_recipient_restrictions =
	reject_unauth_pipelining,
	permit_sasl_authenticated,
	permit_mynetworks,
	warn_if_reject reject_non_fqdn_recipient,
	reject_unknown_recipient_domain,
	reject_unauth_destination

This will log the rejection but still deliever the message.


A Note About Local Addresses.

I have included 'append_at_myorigin = no' to stop Postfix from adding the @domain to my required local addresses. I have added a alias to a real email in my '/etc/aliases' file for root, postmaster, etc... Like so:

echo "root:		[Admin User]@[Admin Domain]" > /etc/aliases
echo "postmaster:	[Admin User]@[Admin Domain]" >> /etc/aliases
newalias

It is done this way because if, in this case, '$myorigin' is listed under 'mydestination', as would be needed for local delivery. Then '$myorigin' would be the same as a domain listed in 'virtual_mailbox_domains', and we...

  • NEVER list a virtual MAILBOX domain name as a mydestination domain!

If none of the domains listed in 'virtual_mailbox_domains' are '$myorigin' then you can remove (or comment out) the 'append_at_myorigin = no' and setup local delivery.

You could also remove (or comment out) the 'append_at_myorigin = no' and make sure that the '$myorigin' virtual domain has a root@'$myorigin', postmaster@'$myorigin', etc account.

OR, remove (or comment out) the 'append_at_myorigin = no' and set up virtual alias maps in the '$myorigin' virtual domain pointing root, postmaster, etc to [Admin User]@[Admin Domain].


The 'mydomain' parameter uses the hostname environment variable, if the hostname command does not return a FQDN, without the --fqdn option, you may not get the correct value for 'mydomain'.  To confirm run the following command:

postconf mydomain
mydomain = localdomain
hostname
gateway

This means that Postfix does not know the FQDN and connot extrapolate the domain. To fix this you could add the domain to your hostname, as follows:

echo [Computer Name].[Domain Name] > /etc/hostname
hostname [Computer Name].[Domain Name]

This will fix the problem and make it persistant, confirm the problem is fixed by running the previous 'postconf mydomain' command again.

You could also simply change the parameter.

postconf -e "myddomain = [Domain Name]"


Testing the Postfix install is similar to testing the Dovecot install.  Open a terminal, not on the server, and try to log into the SMTP server:

telnet [Your IP Address or Domain Name] 25
Trying [Your IP Address]...
Connected to [Your IP Address or Domain Name].
Escape character is '^]'.
220 [Your Gateways FQDN] ESMTP Postfix (Ubuntu)
HELO [Valid Domain Name]
250 [Your Gateways FQDN]
MAIL FROM: [Valid Email]
RCPT TO: [Valid Email From 'passwd' File]
DATA
Type message here.
.

If the email is processed, everything is working correctly.


DONE!!