Random Sequence

Setting up a Debian server as a POP3 mail host for a collection of domains with MySQL, Exim & Courier.

SMTP & POP3 Email for Virtual Users on Debian Sarge

Abstract

I’m setting up a Debian server as a POP3 mail host for a collection of miscellaneous domains. I want to administer the domains & user accounts through a PHP front end, so it’s easiest for me if the configuration is stored in MySQL. After a brief period of reseach, I’m using Exim 4, Courier POP3 + SSL and SpamAssassin.

Below are my notes so far.

Current status:

The server will receive messages on port 25 (or 587) for users in the MySQL database and file them into the correct mailbox. Messages can be downloaded using POP3 using the same database for authentication using plain text authentication (port 110) or SSL (993). Messages can be sent using the server as an SMTP relay providing they authenticate first. TLS is available for sending.

Todo

  1. Quotas
  2. Optional mail forwarding
  3. Write front end for user administration

Notes

Required packages:

sudo apt-get install mysql-server mysql-client libmysqlclient12-dev
sudo apt-get install exim4-daemon-heavy
sudo apt-get install courier-pop-ssl
sudo apt-get install courier-authmysql

If you want to use PHPMyAdmin:

sudo apt-get install apache2
sudo apt-get install apache2-ssl
sudo apt-get install php4
sudo apt-get install phpmyadmin

Create the mail directory

sudo mkdir -m 600 /usr/local/vdomains
sudo chown mail:mail /usr/local/vdomains

Create an example domain

sudo mkdir -m 600 /usr/local/vdomains/example.com
sudo mkdir -m 600 /usr/local/vdomains/example.com/users
sudo chown mail:mail /usr/local/vdomains/example.com

Database

Create a new database called mail, and a user mail with all privileges on that database.

Tables:
CREATE TABLE `domains` (
  `userid` char(128) NOT NULL default '',
  KEY `userid` (`userid`)
) ENGINE=MyISAM;

CREATE TABLE `users` (
  `id` char(128) NOT NULL default '',
  `crypt` char(128) NOT NULL default '',
  `clear` char(128) NOT NULL default '',
  `name` char(128) NOT NULL default '',
  `uid` int(10) unsigned default '8',
  `gid` int(10) unsigned default '8',
  `home` char(255) NOT NULL default '',
  `maildir` char(255) NOT NULL default '',
  `quota` char(255) NOT NULL default '',
  KEY `id` (`id`)
) ENGINE=MyISAM;

Note - I later changed the schema when developing a PHP front end for administration. I found that the id field could be named anything you like, as long as it’s not exactly username. That is: Courier Authdaemon will not authenticate if the id field is named username. These are fine: userName, name, email.

Example User:

INSERT INTO `users` (`id`, `crypt`, `clear`, `name`, `uid`, `gid`, `home`, `maildir`, `quota`) VALUES ('johnnie@example.com', ENCRYPT('johnniepass'), 'johnniepass', 'johnnie', 8, 8, '/usr/local/vdomains/example.com/users/johnnie', '/usr/local/vdomains/example.com/users/johnnie/Maildir/', '');

Note The Maildir field has a trailing slash. Without this exim uses file_transport instead of directory_transport, and you’ll get error messages in the format:

2007-04-04 11:17:43 /usr/local/vdomains/example.com/users/johnnie/Maildir  R=virtual_user defer (-30): file_transport unset in virtual_user router

Make a directory for the user’s data

sudo maildirmake /usr/local/vdomains/example.com/users/johnnie

Configuring Courier

File: /etc/courier/authdaemonrc
Set: authmodulelist="authmysql"

File: /etc/courier/authmysqlrc
Set:

MYSQL_SERVER        localhost
MYSQL_USERNAME  mail
MYSQL_PASSWORD  secret
MYSQL_SOCKET        /var/run/mysqld/mysqld.sock
MYSQL_DATABASE  mail
MYSQL_USER_TABLE    users
MYSQL_CRYPT_PWFIELD crypt
MYSQL_UID_FIELD     uid
MYSQL_GID_FIELD     gid
MYSQL_LOGIN_FIELD   id
MYSQL_HOME_FIELD    home
MYSQL_NAME_FIELD    name

Configuring Exim

Define MySQL server

Edit file: /etc/exim4/conf.d/main/01_exim4-config_listmacrosdefs

Tell Exim which domains it’s handling mail for

# domainlist local_domains = MAIN_LOCAL_DOMAINS
domainlist local_domains = localhost:january.randomsequence.com:mysql;SELECT userid FROM domains WHERE userid='$domain';

New File: /etc/exim4/conf.d/router/999_exim4-config_mysql_user

virtual_user:
    driver = redirect
    allow_fail
    allow_defer
    data = ${lookup mysql{ SELECT maildir FROM users WHERE id='${local_part}@${domain}' }}
    directory_transport = address_directory

virtual_catchall_user:
    driver = redirect
    allow_fail
    allow_defer
    data = ${lookup mysql{ SELECT maildir FROM users WHERE id='*@${domain}' }}
    directory_transport = address_directory

Edit File: /etc/exim4/conf.d/transport/35_exim4-config_address_directory

# This transport is used for handling file addresses generated by alias
# or .forward files if the path ends in "/", which causes it to be treated
# as a directory name rather than a file name.

address_directory:
  debug_print = "T: address_directory for $local_part@$domain"
  driver = appendfile
  envelope_to_add = true
  return_path_add = true
  check_string = ""
  escape_string = ""
  maildir_format = true
  mode = 0600
  user = mail
  group = mail

Allow remote connections to Exim

Edit file: /etc/exim4/update-exim4.conf.conf

# …snip
# This is a Debian specific file

dc_eximconfig_configtype='internet'
dc_other_hostnames=''
dc_local_interfaces='127.0.0.1:[SERVER IP ADDRESS]'
dc_readhost=''
dc_relay_domains=''
dc_minimaldns='false'
dc_relay_nets=''
CFILEMODE='644'
dc_use_split_config='true'
dc_hide_mailname='false'
dc_mailname_in_oh='true'

Removing Lookup Delays

Edit file: /etc/exim4/conf.d/main/02_exim4-config_options
Set: rfc1413_query_timeout = 0s

Allow Exim to use Courier Authdaemon

Add Exim to the daemon group:

sudo usermod -G daemon Debian-exim

Edit file: /etc/exim4/conf.d/auth/30_exim4-config_examples

Un-comment plain_courier_authdaemon: & login_courier_authdaemon:, comment out cram_md5:, plain: & login: sections.

Enable Exim TLS

Generate a self-signed certificate for Exim using the tool:
/usr/share/doc/exim4-base/examples/exim-gencert

New file: /etc/exim4/conf.d/main/000_localmacros

# switch on tls
MAIN_TLS_ENABLE = true

# Listen on Standard TLS Port
daemon_smtp_ports = smtp : 587

#enable login without TLS / SSL
AUTH_SERVER_ALLOW_NOTLS_PASSWORDS = true

SpamAssassin

To install the latest spamassassin with sa-update, it was necessary to use the unstable Debian branch. This my come back to haunt me.

Add Unstable Source

Edit file: /etc/apt/sources.list

deb http://ftp.us.debian.org/debian unstable main non-free contrib

Make sure we use stable packages by default for everything else:
Edit file: /etc/apt/apt.conf

APT::Default-Release "stable";

Install spamassain & required packages for sa-update

sudo apt-get install -t unstable spamassassin
sudo apt-get install libnet-dns-perl gnupg 

This involves upgrading a bunch of other libraries to unstable, and therefore probably isn’t a good idea.

Start spamd each reboot

Edit file: /etc/default/spamassassin

# Change to one to enable spamd
ENABLED=1

Enable SpamAssassin in Exim

Edit file: /etc/exim4/sa-exim.conf

# Remove or comment out the following line to enable sa-exim
# SAEximRunCond: 0

Cron Job for sa-update

New file: /etc/cron.daily/sa-update

#!/bin/sh
# Update SpamAssassin Rules

/usr/bin/sa-update -D channel,dns
/etc/init.d/spamassassin restart

Run the update now:

sudo /usr/bin/sa-update -D channel,dns

Training SpamAssassin

sudo sa-learn --showdots --spam folder_of_spam/*
sudo sa-learn --showdots --ham folder_of_ham/*

Starting SpamAssassin

sudo /etc/init.d/spamassassin start

Dubugging Exim problems

Enable extended logging (to file /var/log/exim4/mainlog):
File: /etc/exim4/conf.d/main/02_exim4-config_options
Set: log_selector = +all

# Show log for a particular message: 
sudo /usr/sbin/exim4 -Mvl [Message ID]

# Force Exim to process the mail queue: 
sudo /usr/sbin/exim4 -qf

Helpful Links

http://www.tty1.net/virtual_domains_en.html
http://koivi.com/exim4-config/
http://www.sput.nl/software/exim.html
http://bradthemad.org/tech/notes/exim_cheatsheet.php?FOO
http://swik.net/Exim
http://www.exim.org/exim-html-4.10/doc/html/spec_toc.html

Sponsored Links: