Author: Psand Limited
Updated By: $Author: nelf $
Date: $Date: 2005/03/12 17:25:36 $
Version: $Revision: 1.1 $
We've been running email services on Unix since 1997 when we took over the maintenance of a Sun SPARC Ultra/1 box running Solaris 2.5.1. The configuration was simple and old-fashioned. It used Unix user accounts without home directories or login shells as the email accounts and Sendmail. The only service provide was POP3; not having IMAP meant no home directories for the users.
About a year after taking it over we migrated to a Intel based server running Linux and have never looked back. The configuration is essentially the same as it was back in 1997. Yes, there have been some additions. For instance, it now provides IMAP to those who want it, hence home directories; the Horde-IMP framework has been implemented to provide web mail services; Majordomo runs to manage a couple of mailing lists; we use Mhonarc to archive some mails; and a couple of the email accounts run SpamAssassin in an attempt to curtail the ever increasing Spam problem. These extras have been 'bolted-on' to the existing building block of Sendmail+Unix accounts in a haphazard manner, not incorrectly installed, but in many cases these services are still running as 'beta' and not offered to everybody.
Currently there are something in the range of 190 individual email accounts, for 130 domains with 250 virtual user aliases. It's not a big system, but it's out of date and given that managing the mail server is not something we have a lot of time to do (spare or work), it's got out of hand, not in the least because of the large amount of Spam that seems to circulate around the network. The mail traffic report generated by AWStats for April 2004 shows a total of 79,581 emails sent and 19,141 rejected, totally approximately 5GB of traffic, which seems to be quite a lot to me.
With all this in mind, we felt that it was about time that we had a shiny new mail server with all the latest in services and Spam protection. In this document we hope to detail what we chose to use and why and what my experiences were with getting it working.
For reference, the server in question is running Debian GNU/Linux 3.0 (Woody) with kernel version 2.4.25, so these instructions are tested on Debian; however, we believe they should work on all Linux distributions (at least those with a 2.4.x kernel) as well as *BSD, Mac OS X and the hoard of other Unicen out there.
Bit duff this section, perhaps remove?
We've had the Exim MTA running for quite a while on one of our test servers. It seems to be good, light-weight and much easier to manage than Sendmail. So we chose it. There are others we know, Postfix, Qmail etc, but we don't have time to test them all and in short, Exim is good, it works and it's my choice here. Sendmail's been a faithful servant over the years, but the arthritis is setting in and we think that it's been high-time to move onto pastures new for quite a while now.
Testing installation:
apt-get install exim-tls mailx
Send an email to the user (adelayde@mango.psand.net). Then check this box on the server (/var/spool/mail/adelayde) does the message arrive okay? Cool Exim is working.
How to recognise recipient names?
Seems like a good package, Cyrus uses it's own directory structure, so bang go the Unix home directories. By default it handles authentication through either Unix shadow passwords or Kerberos. The latter seems a little bit too complicated for this set-up and yet something else to learn and the former is what we're trying to get away from. So we need it to authenticate against our MySQL database.
It all comes in deb packages, so get apt-getting:
apt-get install cyrus-imapd cyrus-common cyrus-pop3d cyrus-admin
By default, Cyrus authenticates against SASL using its own internal DB file, read the file /usr/share/doc/cyrus21-doc/README.Debian.simpleinstall.gz for handy tips. Key point is to set-up the cyrus user:
sasl_mech_list: PLAIN DIGEST-MD5 CRAM-MD5
sasl_minimum_layer: 0
sasl_pwcheck_method: auxprop
First: Read the file /usr/share/doc/libsasl2/index.html
Second, note that we're not using PAM authentication here as we previously thought, mainly because we can't get this to work. It's enough (and perhaps simpler) to do just SASL+MySQL. Nonetheless in the next bit, I've detailed the Cyrus+PAM+MySQL notes.
Go back and edit the imapd.conf file and change the following:
sasl_mech_list: PLAIN DIGEST-MD5 CRAM-MD5
sasl_minimum_layer: 0
sasl_pwcheck_method: auxprop
sasl_auxprop_plugin: sql
sasl_sql_engine: mysql
sasl_sql_hostnames: localhost
sasl_sql_user: cyrus
sasl_sql_passwd: *********
sasl_sql_database: exim
sasl_sql_select: SELECT password AS userPassword FROM users WHERE username = '%u' AND enabled = '1'
And restart the IMAP daemon to read in the new settings:
/etc/init.d/imap restart
Now create a database and table for authenticating your IMAP/POP3 mailbox users, for example:
USE exim;
CREATE TABLE users (
id INT(11) NOT NULL AUTO_INCREMENT,
username VARCHAR(15) DEFAULT '' NOT NULL,
password VARCHAR(15) DEFAULT '' NOT NULL,
enabled TINYINT DEFAULT 1 NOT NULL,
email VARCHAR(40) DEFAULT '' NOT NULL,
name VARCHAR(50) DEFAULT '' NOT NULL,
company VARCHAR(30) DEFAULT '' NOT NULL,
tel1 VARCHAR(15) DEFAULT '' NOT NULL,
tel2 VARCHAR(15) DEFAULT '' NOT NULL,
domain VARCHAR(40) DEFAULT '' NOT NULL,
PRIMARY KEY (id)
) TYPE=MyISAM;
Forth thing, grant permission to a user in MySQL:
GRANT SELECT, INDEX, INSERT, UPDATE, DELETE ON exim.users TO cyrus@localhost IDENTIFIED BY 'cyrusIMAP';
FLUSH PRIVILEGES
Now you add users to the exim.users table:
INSERT INTO users (username, password) VALUES ('username1','password1');
You can encrypt the password by putting the result of the following in instead of the plain text password:
SELECT PASSWORD('password1');
Will return an encyrpted string (i.e. 6C5acede3d3de7e4), use this in the INSERT statement above.
NOTE: ** we found it not to work with MySQL PASSWORD authentication, not sure why, so we used the built-in MD5 encryption instead, i.e.:
a. mkpasswd password1
b. udpate mysql table.
c. change crypt=1 in cyrus config.
Having done that it then should really just work. You can try using the cyradm command for your user:
cyradm -u cyrus mango.psand.net
Note in order that a user can login via cyradm, you must list the username in the file /etc/imap.conf, under the entry 'admins:', for example:
admins: user1
This can be done by using PAM. Cyrus can authenticate against PAM and PAM has a MySQL plug-in for authenticating against a database. Check out http://www.delouw.ch/linux/Postfix-Cyrus-Web-cyradm-HOWTO/html/pam-config.html for some information on this. We went for SASL, but here are the details for the PAM way, which in the end didn't see to work very well.
Edit /etc/pam.d/cyrus and replace the lines:
auth required pam_unix.so nullok
account required pam_unix.so
with:
auth sufficient pam_mysql.so user=cyrus passwd=******* \
host=localhost db=mailusers table=mailusers usercolumn=username \
passwdcolumn=password crypt=0 where=enabled=1
account required pam_mysql.so user=cyrus passwd=******* \
host=localhost db=mailusers table=mailusers usercolumn=username \
passwdcolumn=password crypt=0 where=enabled=1
Then do update-alternatives --display pwcheck
and if it returns 'link currently points to /usr/sbin/pwcheck_standard'
do,
update-alternatives --config pwcheck
and you'll see:
There are 2 programs which provide `pwcheck'.
Selection Command
-----------------------------------------------
*+ 1 /usr/sbin/pwcheck_standard
2 /usr/sbin/pwcheck_pam
Enter to keep the default[*], or type selection number:
and type in '2':
you'll get:
Using `/usr/sbin/pwcheck_pam' to provide `pwcheck'.
So do then,
/etc/init.d/pwcheck restart
Test the connexion locally:
cyradm -user cyrus localhost
To add TLS/SSL support to your server, you need to again edit imapd.conf and set the following options:
tls_cert_file: /etc/ssl/certs/cyrus-global.pem
tls_key_file: /etc/ssl/private/cyrus-global.key
tls_ca_path: /etc/ssl/certs
tls_session_timeout: 1440
tls_cipher_list: TLSv1:SSLv3:SSLv2:!NULL:!EXPORT:!DES:!LOW:@STRENGTH
Now we need to create the key file and certificate. To do this we need to use Open SSL:
cd /etc/ssl/
openssl req -new -nodes -out certs/cyrus-global.csr \
-keyout private/cyrus-global.key
openssl rsa -in private/cyrus-global.key \
-out private/cyrus-global.key
openssl x509 -in certs/cyrus-global.csr \
-out certs/cyrus-global.pem -req \
-signkey private/cyrus-global.key -days 3650
chgrp mail private
chmod g+rx private
chmod o-rwx private/cyrus-global.key
Note, in the above, need to check the security aspects of allowing access to mail user to that directory. Unfortunately the documentation suggests the above, but also under Debian, cyrus process runs as group 'mail'. There's probably some handy deb script or package for the above, but we couldn't find it.
To make Exim use Cyrus for the delivery of email messages add the following to your /etc/exim/exim.conf file (and comment out the default entry for 'local_delivery') Really this is now out of the correct order, as this uses MYSQL to deal with the local users see towards the end of the document for information about this:
virtual_local_md_delivery:
driver = pipe
command = /usr/sbin/cyrdeliver \
"${lookup mysql {MYSQL_Q_BOXNAME}{$value}}"
user= cyrus
group = mail
return_fail_output
log_output
message_prefix =
message_suffix =
10.How to make Exim authenticate the incoming user against mysql?
1.Create the following MySQL table in the mailusers database:
CREATE TABLE virtusers (
id int(11) NOT NULL auto_increment,
localpart varchar(20) DEFAULT '' NOT NULL,
domain VARCHAR(50) DEFAULT '' NOT NULL,
enabled TINYINT DEFAULT 1 NOT NULL,
target VARCHAR(100) DEFAULT '' NOT NULL,
name varchar(50) DEFAULT '' NOT NULL,
company varchar(30) DEFAULT '' NOT NULL,
tel1 varchar(15) DEFAULT '' NOT NULL,
tel2 varchar(15) DEFAULT '' NOT NULL,
PRIMARY KEY (id)
) TYPE=MyISAM;
2.Here's some test users:
See below in the exim section.
3.Exim.conf configuration for this:
See below
Exim is great, but it's not so great that you don't need to submerge your brain in a bucket of LSD to get your head round how it all works... mail is not simple, but exim tackles the whole thing in a reasonably sensible, flexible and well documented way.
Here follows a list of desirable features from Exim:
| Feature | Status | Description |
| Virtual Users | Fully Implemented | any_user@any_domain domain can have mail delivered to any local cyrus mailbox or redirected elsewhere. |
| Spam filtering | Fully implemented (spamassassin) | Any mail considered to be spam is marked as such and can thus be filtered into a spam mailbox by the user's client machine |
| Spam dumping (spammassissin) | Implemented, but not tested | Any mail considered to be spam will be dumped automatically into /dev/null |
| Away messages | Implemented but not tested | A virtual user can be marked as away and a customisable message is sent back to the sender |
| Virus Scanning | Transport implemented, virus scanner not implemented | Mails containing viruses will be blocked |
| Disabling of accounts | Implemented but not tested | Any particular virtual user can be disabled temporarily without removing the virtuser entry. |
| SMTP service for clients | Fully implemented | A user anywhere can use the server as a relay if they have the right secret knowledge |
| TLS | Fully implemented | All services should be available over an encrypted SSL/TLS connection |
As you might expect, exim is started using the following command:
# invoke-rc.d exim4 start
If you want to send any extra command line parameters to the daemon, then you should use the /etc/defaults/exim4 file to do so. A particularly useful one is the '-v' option that causes the exim daemon to keep STDOUT open when you run invoke-rc.d exim4 start and you can see lots of information about what is happening... you put this in the 'SMTPLISTENEROPTIONS section of the /etc/default/exim4 file.
This is the 'meta configuration' file... not a lot gets set here, but what does get set is very important. It's a small file and I'll include it here for completeness - I've added comments at the end of each line to help understand what goes on:
# /etc/exim4/update-exim4.conf.conf
#
# Edit this file and /etc/mailname by hand and execute update-exim4.conf
# yourself or use 'dpkg-reconfigure exim4-config'
dc_eximconfig_configtype='internet'
dc_other_hostnames='psand.net,iain.biz'
dc_local_interfaces=''
dc_readhost=''
dc_relay_domains='nelf.net'
dc_minimaldns='false'
dc_relay_nets='194.164.97.0/24' # Who is allowed to use the server without authenticating
dc_smarthost=''
CFILEMODE='644'
dc_use_split_config='false' # For different approaches to configuration file layout
Basic configuration is defined in this file. This is where the exim binaries are defined, log and spool files are defined, the users that are allowed to fiddle with mail, MYSQL connections and statements are defined here too. See below for a description of how the MYSQL stuff works.
The following is the set of mysql tables used by exim to handle virtual users, etc. These tables are all in a database called exim so as not to interfere with any of Mikes setup:
| virtualusers | Each row defines a single 'virtual user', and what is going on with them (ie the local part and domain part, which mailbox the mail is sent to, whether it is virus scanned and spam scanned, whether that virtual user is away or not and the message that is displayed etc etc. |
| domaintable | Very simple table that says which domains exim will deal with - equivalent of local domains in sendmail |
| users | Very simple table that defines user names and passwords for the actual mailboxes, used by Cyrus to authenticate users via IMAP or POP3. Table also contains some extra fields for the reference of administrators. This is equivalent of UNIX user accounts and the /etc/passwd file. |
| relaytable | Simple table which defines which domains this server will relay for (rarely used) |
| whitelist | This contains addresses that should never be filtered out as spam. |
| blacklist | This blacklists certain sender addresses and prevents mail from being processed that has this sender in it. |
create database exim;
CREATE TABLE `virtualuserss` (
`local_part` varchar(20) NOT NULL default '',
`domain` varchar(30) NOT NULL default '',
`forward` varchar(50) NOT NULL default '',
`box` varchar(30) default NULL,
`is_away` enum('yes','no') NOT NULL default 'no',
`away_text` tinytext NOT NULL,
`is_enabled` enum('yes','no') NOT NULL default 'yes',
`opt_virscan` enum('yes','no') NOT NULL default 'no',
`opt_spamscan` enum('yes','no') NOT NULL default 'yes',
`opt_spampurge` enum('yes','no') NOT NULL default 'no',
`lc_ts` int(11) NOT NULL default '0',
`lc_ip` varchar(15) NOT NULL default '',
`create_ts` int(11) NOT NULL default '0'
) TYPE=MyISAM;
CREATE TABLE `domaintable` (
`domain` varchar(30) NOT NULL default ''
) TYPE=MyISAM;
CREATE TABLE `relaytable` (
`domain` varchar(50) NOT NULL default ''
) TYPE=MyISAM;
CREATE TABLE `whitelist` (
`address` varchar(50) NOT NULL default ''
) TYPE=MyISAM;
CREATE TABLE `blacklist` (
`address` varchar(50) NOT NULL default ''
) TYPE=MyISAM;
The MYSQL connection and statements are at the top of the /etc/exim4/exim4.conf.template:
# MySQL defines
MYSQL_SERVER=localhost
MYSQL_USER=exim
MYSQL_PASSWORD=*******
MYSQL_DB=exim
MYSQL_EMAILTABLE=virtualusers
MYSQL_DOMAINTABLE=domaintable
MYSQL_DOMAINRTABLE=relaytable
MYSQL_WHITETABLE=whitelist
MYSQL_BLACKTABLE=blacklist
MYSQL_AUTHTABLE=boxauth
# MySQL queries
MYSQL_Q_ISAWAY=SELECT domain FROM MYSQL_EMAILTABLE WHERE domain='${quote_mysql:$domain}' \
AND local_part='${quote_mysql:$local_part}' AND is_away='yes'
MYSQL_Q_AWAYTEXT=SELECT away_text FROM MYSQL_EMAILTABLE WHERE domain='${quote_mysql:$domain}' \
AND local_part='${quote_mysql:$local_part}'
MYSQL_Q_FORWARD=SELECT forward FROM MYSQL_EMAILTABLE WHERE domain='${quote_mysql:$domain}' \
º AND local_part='${quote_mysql:$local_part}' AND forward != ''
MYSQL_Q_LOCAL=SELECT domain FROM MYSQL_EMAILTABLE WHERE domain='${quote_mysql:$domain}' \
AND local_part='${quote_mysql:$local_part}' AND box != ''
MYSQL_Q_WCLOCAL=SELECT domain FROM MYSQL_EMAILTABLE WHERE domain='${quote_mysql:$domain}' \
AND local_part='*' AND box != ''
MYSQL_Q_WCLOCFW=SELECT forward FROM MYSQL_EMAILTABLE WHERE domain='${quote_mysql:$domain}' \
AND local_part='*' AND forward != ''
MYSQL_Q_LDOMAIN=SELECT DISTINCT domain FROM MYSQL_DOMAINTABLE WHERE domain='$domain'
MYSQL_Q_RDOMAIN=SELECT DISTINCT domain FROM MYSQL_DOMAINRTABLE WHERE domain='$domain'
MYSQL_Q_BOXNAME=SELECT box FROM MYSQL_EMAILTABLE WHERE domain='${quote_mysql:$domain}' \
AND local_part='${quote_mysql:$local_part}'
MYSQL_Q_SPAMC=SELECT domain FROM MYSQL_EMAILTABLE WHERE domain='${quote_mysql:$domain}' \
AND local_part='${quote_mysql:$local_part}' AND opt_spamscan='yes'
MYSQL_Q_VSCAN=SELECT domain FROM MYSQL_EMAILTABLE WHERE domain='${quote_mysql:$domain}' \
AND local_part='${quote_mysql:$local_part}' AND opt_virscan='yes'
MYSQL_Q_SPAMPURGE=SELECT domain FROM MYSQL_EMAILTABLE WHERE domain='${quote_mysql:$domain}' \
AND local_part='${quote_mysql:$local_part}' AND opt_spampurge='yes'
MYSQL_Q_DISABLED=SELECT domain FROM MYSQL_EMAILTABLE WHERE domain='${quote_mysql:$domain}' \
AND local_part='${quote_mysql:$local_part}' AND is_enabled='no'
MYSQL_Q_WHITELIST=SELECT DISTINCT MYSQL_WHITETABLE.address FROM MYSQL_WHITETABLE \
WHERE whitelist.address='${quote_mysql:$sender_address}' \
OR whitelist.address='*@${quote_mysql:$sender_address_domain}'
MYSQL_Q_BLACKLIST=SELECT MYSQL_BLACKTABLE.address FROM MYSQL_BLACKTABLE \
WHERE blacklist.address='${quote_mysql:$sender_address}' \
OR blacklist.address='*@${domain:${quote_mysql:$sender_address}}' LIMIT 1
MYSQL_Q_AUTHPWD1=SELECT boxname FROM MYSQL_AUTHTABLE WHERE boxname='$2' AND boxpwd=encrypt('$3',boxpwd)
MYSQL_Q_AUTHPWD2=SELECT boxname FROM MYSQL_AUTHTABLE WHERE boxname='$1' AND boxpwd=encrypt('$2',boxpwd)
# MySQL connection
hide mysql_servers = "MYSQL_SERVER/MYSQL_DB/MYSQL_USER/MYSQL_PASSWORD"
Here is how the domaintable is used to determine whether an incoming domain is local or not:
domainlist local_domains = mysql;MYSQL_Q_LDOMAIN
######################################################################
# ROUTERS CONFIGURATION #
# Specifies how addresses are handled #
######################################################################
# THE ORDER IN WHICH THE ROUTERS ARE DEFINED IS IMPORTANT! #
# An address is passed to each router in turn until it is accepted. #
######################################################################
begin routers
fail_router:
debug_print = "R: fail_router for $local_part@$domain"
driver = redirect
domains = ${lookup mysql {MYSQL_Q_DISABLED}{$value}}
data = ":fail:"
allow_fail
...
...
blacklist_router:
debug_print = "R: blacklist_router for $local_part@$domain"
driver = manualroute
senders = ${lookup mysql {MYSQL_Q_BLACKLIST}{$value}}
condition = "${if !def:h_X-Spam-Flag: {1}{0}}"
headers_add = X-Spam-Flag: YES
route_list = * localhost
self = pass
...
...
spamcheck_director:
debug_print = "R: spamcheck_director for $local_part@$domain"
driver = manualroute
domains = ${lookup mysql {MYSQL_Q_SPAMC}{$value}}
senders = ! ${lookup mysql {MYSQL_Q_WHITELIST}{$value}}
condition = ${if and { {!def:h_X-Spam-Flag:} {!eq {$received_protocol}{spam-s\
canned}} {!eq {$received_protocol}{local}} } {1}{0}}
route_list = "* localhost byname"
transport = spamcheck
verify = false
spampurge_director:
driver = manualroute
domains = ${lookup mysql {MYSQL_Q_SPAMPURGE}{$value}}
condition = "${if eq{$h_X-Spam-Flag:}{YES} {1}{0}}"
route_list = "* localhost byname"
transport = devnull_transport
verify = false
vacation_director:
driver = accept
domains = ${lookup mysql {MYSQL_Q_ISAWAY}{$value}}
transport = vacation_autoreply
unseen
virtual_forward_director:
driver = redirect
data = ${lookup mysql {MYSQL_Q_FORWARD}{$value}}
virtual_local_mailbox:
debug_print = "R: virtual_local_mailbox for $local_part@$domain"
driver = accept
domains = ${lookup mysql {MYSQL_Q_LOCAL}{$value}}
transport = virtual_local_md_delivery
virtual_wclocal_redirect:
driver = redirect
domains = ${lookup mysql {MYSQL_Q_WCLOCAL}{$value}}
data = ${lookup mysql {MYSQL_Q_WCLOCFW}{$value}}
Firstly, all actual mail is delivered by exim to CYRUS, so if no CYRUS mailbox exists, then things are going to go very badly indeed!
Assuming a cyrus mailbox called 'brian' exists, in order to make exim accept mail for brianjones@whoknows.com the following things need to be done:
Add the domain part to the exim.domaintable table:
INSERT INTO domaintable set domain='whoknows.com';
Now set up the virtual user part:
INSERT INTO virtualusers SET local_part='brianjones', \
domain='slackmail.co.uk', box='brian', opt_spamscan='yes';
Before we start, you really ought to have some web servers running:
apt-get install apache-ssl apache logrotate
The Debian packages work fine, but can confuse you if you're already familiar with Horde as it moves things around. Firstly let's install it:
apt-get install horde2 imp3 turba kronolith mnemo nag
Now you'll find that you have the following:
Which is pretty sensible when you think that the config files are put in a much more secure place by default on Debian. Anyway on with the show:
Here we're going to use the SSL enabled version of Apache, you really wouldn't want to use the non-SSL version. Firstly need to edit our Apache-SSL configuration to enable PHP support and use Horde, so bring up /etc/httpds.conf in your favourite editor.
Look for the following line and make sure it's uncommented:
AddType application/x-httpd-php .php
Look for the DirectoryIndex directive and make index.php the home page:
<IfModule mod_dir.c>
DirectoryIndex index.php index.html
</IfModule>
Change DocumentRoot:
DocumentRoot /usr/share/horde2/imp/
Change the Directory entry for the above:
<Directory /var/www/horde2/imp/>
....
....
</Directory>
Check right at the bottom of the file that the Horde config is included:
Include /etc/horde2/apache.conf
Now we need to make sure that the PHP4 module is loaded, by default under Debian it doesn't see to get added to the list of modules, so do this manually. Edit /etc/apache-ssl/modules.conf and insert the following line at the bottom of it:
LoadModule php4_module /usr/lib/apache/1.3/libphp4.so
While you're there, I'd also recommend commenting out a few things we don't need and could be considered insecure:
# LoadModule status_module /usr/lib/apache/1.3/mod_status.so
# LoadModule autoindex_module /usr/lib/apache/1.3/mod_autoindex.so
# LoadModule userdir_module /usr/lib/apache/1.3/mod_userdir.so
Last but not least, and returning to httpd.conf, there seems to be a bug in the default Debian install of Apache-SSL (at the time of writing), it seems that all modules.conf loads the SSL version of mod_mime, httpd.conf still looks for the non-SSL version. The net result is that the PHP file type isn't recognised as is therefore sent to you to be downloaded, rather than being run. To fix this, change the following line:
<IfModule mod_mime.c>
To read ...
<IfModule mod_mime_ssl.c>
Next we need to produce a signed SSL certificate for Apache and set-up our httpd.conf file to use it. You may wish to spunk your money on paying one of the many organisations that sign certificates. However here we self-sign them and save ourselves some wonga:
# cd /etc/apache-ssl/
# openssl genrsa -out /etc/ssl/private/www.yourwebmaildomain.com.key 1024
# openssl req -new -key www.yourwebmaildomain.com.key -out www.yourwebmaildomain.com.csr
You'll be asked to provide information for the certificate, I for example used the following for our web mail set-up. Obviously customise this to suit your specific site:
Country Name (2 letter code) [AU]:UK
State or Province Name (full name) [Some-State]:Kent
Locality Name (eg, city) []:Ramsgate
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Psand Ltd
Organizational Unit Name (eg, section) []:Slackmail
Common Name (eg, YOUR name) []:www.slackmail.co.uk
Email Address []:support@psand.net
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
At this stage, if you were to buy a third-party-signed certificate, you would send the .key file to the signer and wait for a .csr file to come back. In this case we sign it ourselves.
# openssl X509 -req -days 1825 -in www.yourwebmaildomain.com.csr -signkey www.yourwebmaildomain.com.key -out www.yourwebmaildomain.com.crt
Note in the above command, I specified 1,825 days or five years. You can choose yourself how long you'd like the certificate to last. If it all worked okay you should get something like the following as the result:
Signature ok
subject=/C=UK/ST=Kent/L=Ramsgate/O=Psand Ltd/OU=Slackmail/CN=www.slackmail.co.uk/emailAddress=support@psand.net
Getting Private key
Now edit the file /etc/apache-ssl/httpd.conf and change/create the following lines:
SSLCertificateFile /etc/apache-ssl/www.yourwebmaildomain.com.crt
SSLCertificateKeyFile /etc/ssl/private/www.yourwebmaildomain.com.key
Restarting Apache-SSL should mean that it will work to some extent, you can test horde in your browser by visiting 'http://hostname/horde/test.php
We did this and got some warning about missing packages. We then went about installing some more debian modules:
apt-get install php-file php-date php-mcyrpt php-domxml php-mcal
And some PEAR modules:
pear install Mail_Mime
pear install Net_Socket
pear install Log
I needed to do 'pear config-set preferred_state beta' in order to be able to then install and just in case, I set the package status back again afterwards:
pear config-set preferred_state beta
pear install HTML_Common
pear install HTML_Select
pear config-set preferred_state stable
And restarted the web server again.
Horde needs access to the 'horde2' database in MySQL to save various session things, including user preferences (keyed by email address). The file which controls this (if you ever wish to change the password or user) is /var/lib/horde2/horde-debian.php and our current settings are:
$conf['prefs']['driver'] = 'sql';
$conf['prefs']['params']['phptype'] = 'mysql';
$conf['prefs']['params']['hostspec'] = 'localhost';
$conf['prefs']['params']['username'] = 'horde';
$conf['prefs']['params']['password'] = '*******';
$conf['prefs']['params']['database'] = 'horde2';
$conf['prefs']['params']['port'] = '3306';
$conf['prefs']['params']['table'] = 'horde_prefs';
Now on with IMP, first edit /etc/horde/registry.php to allow IMP to handle Horde logging in, done by looking for and enabling the following lines:
$this->registry['auth']['login'] = 'imp';
$this->registry['auth']['logout'] = 'imp';
Decided to add a few extra email headers to show more about where the message came from and to send extra information, edit file /usr/share/horde2/imp/config/header.txt and add:
X-WebMail-Company: Psand Ltd. (www.psand.net)
X-Originating-IP: %REMOTE_ADDR%
X-Originating-UA: %HTTP_USER_AGENT%
At this point you can also edit the text that is always postpended to each mail sent from IMP. The contents are in the file /usr/share/horde2/imp/config/trailer.txt.
Lastly to enable and disable these headers and trailers, you edit the file /etc/imp3/conf.php. In this instance, I enabled (or kept) the header, but disabled the trailer:
$conf['msg']['prepend_header'] = true;
$conf['msg']['append_trailer'] = false;
Test your IMP set-up with by visiting https://slackmail.psand.net/horde/imp/test.php
From this page, you could try entering the following values for testing against a Cyrus IMAP server with TLS support:
Server: mango.psand.net
Protocol: imap/ssl/novalidate-cert
Port: 993
User: user1
Password: password1
If that worked, you can connect to Cyrus IMAP via IMP fine, so now we can edit the default server that it authenticates against for login. Edit the file /var/lib/imp3/servers-debian.conf and change the entry that's in there to read like below:
$servers['imap'] = array(
'name' => 'IMAP Server',
'server' => 'localhost',
'protocol' => 'imap/ssl/novalidate-cert',
'port' => 993,
'folders' => 'INBOX.',
'namespace' => '',
'smtphost' => 'localhost',
'maildomain' => 'psand.net',
'realm' => 'psand.net',
'preferred' => ''
);
In /etc/horde2/horde.php set the email address for reporting problems:
$conf['problems']['enabled'] = true;
$conf['problems']['email'] = 'support@slackmail.co.uk';
In /etc/imp3/conf.php, there's a few things one can change:
$conf['user']['select_sentmail_folder'] = true;
$conf['user']['allow_resume_all_in_drafts'] = true;
$conf['spam']['reporting'] = true;
// $conf['spam']['email'] ....
$conf['spam']['program'] = '/usr/bin/spamassassin -r';
We support people who speak different languages than English. Now although many people can understand English to a greater or lesser degree, it is still important to provide them where possible with tools in their language; very often people have a grasp of English and not full comprehension of it, therefore they might miss an important piece of information, also in my experience people tend to prefer things in their own language as they feel less colonialised. Anyway there's two parts to this, getting Horde and IMP's interfaces to appear in the language of the user's choice and getting in to support spell checking in languages other than American.
Firstly, you're going to need to make sure that the server has the relevant packages, for this we do some apt-getting, starting with some spelling dictionaries (most supported languages I'll install, that gives us the best support for all our users):
apt-get install ispell iamerican ibrazilian ibritish ibulgarian \
iczech icatalan idutch iesperanto ifaroese ifinnish ifrench igaelic \
ihungarian iirish iitalian ilithuanian imanx ingerman inorwegian \
ipolish iportuguese irussian ispanish iswedish iukrainian \
brazilian-conjugate wbulgarian wcatalan wdutch wfaroese wfinnish \
wfrench witalian wngerman wpolish wspanish wswedish wukrainian
Now we enable IMP to use ispell by editing the file /etc/imp3/conf/ and setting the following:
$conf['utils']['spellchecker'] = 'ispell';
To take advantage of Horde's multi-lingual support, we need gettext:
apt-get install gettext gettext-doc gettext-base gettext-el
Next up is installing the locales on the system so that Horde can use them to display it's interface in different languages, let's get apt-getting again:
apt-get install locales
Skip the configuration for this (cancel it), you can always run it later using the command 'dpkg-reconfigure locales'. However there's no real reason to do this, selecting all the locales from the list is a bind, there's a short-cut you can use to generate all the supported locales:
cat /usr/share/i18n/SUPPORTED >> /etc/locale.gen
Open the file /etc/locale.gen in your favourite text editor, search for the locale byn_ER UTF-8 and comment it out or remove it. Now do:
locale-gen
That may take a few minutes. Once done, you then need to make sure PHP supports gettext. This took me most of a day to figure out as I couldn't find explicit 'dependencies' in the instructions. I eventually found it in the Horde FAQ under SUSE. Anyway, what you need to do is to edit /etc/php/apache/php.ini and under the extensions setion add:
extension=gettext.so
and restart your web server.
Now we set our preferred language to use, in our case British English, do this by editing /etc/horde2/lang.php:
$nls['defaults']['language'] = 'en_GB';
Also in this file there's a setting for the dictionary to use, ispell has a Catalan dictionary, but we need to add it for IMP:
$nls['spelling']['ca_ES'] = '-d catalan';
Need to install some file viewers to view PDF, Word etc on the fly in one's browser window. This is done by doing an 'apt-get install wv ppthtml enscript zip unzip rar pdftohtml' and then by editing /etc/horde2/mime_drivers.php and the changing the following:
$mime_drivers_map['horde']['registered'] = array( 'php', 'tgz', 'vcard', 'enriched', 'images' ,'msword', 'msexcel', 'mspowerpoint' ,'enscript', 'tar', 'zip', 'rar' , 'rpm', 'deb' );
Then find the section beginning $mime_drivers['horde']['msword']['location'] ... and uncomment that. Then do the same for the xlhtml (excel) section and change the path to the exe, removing the local part:
$mime_drivers['horde']['msexcel']['location'] = '/usr/bin/xlhtml';and for powerpoint
$mime_drivers['horde']['mspowerpoint']['location'] = '/usr/bin/ppthtml';
Zip might be interesing too, tar, rar etc, at the moment, word and ppt work fine, excel don't (mime type?) and zip+tar etc to do. Done Zip, Tgz, PDF Excel support, Vcards too, some changes, doesn't seem that mail clients send correct mime tyep.
I like the UNIX fortune command that displays quotes and adages at random and thought it'd be nice to have it on the login screen. To make this work, let's apt-get the packages, again supporting as many languages as possible:
apt-get install fortune fortunes fortunes-es fortunes-eo-ascii \
fortunes-fr fortunes-it fortunes-pl fortune-zh fortunes-br \
fortunes-de fortunes-cs fortunes-ga
To make it appear, edit the file /etc/imp3/motd.php and add the following at the end of the file but before the closing '?>':
echo '<hr/><pre align="center" class="light"">';
system('/usr/games/fortune');
echo '</pre>';
It's handy for the user if all the available Horde applications appear on the menus when in each of them, making navigation easier. You do this by editing the conf.php for each of the applications (/etc/imp3/conf.php, /etc/nag/conf.php, etc). An example entry for IMP is:
$conf['menu']['apps'] = array('turba','kronolith','nag','mnemo');
And finally you need to make all the applications active and also change their names if you so desire, you do this by editing the application specific files in /etc/horde2/registry.d/, for example, for IMP you edit imp.php and change the entry to:
$this->applications['imp'] = array(
'fileroot' => '/usr/share/horde2/imp',
'webroot' => $this->applications['horde']['webroot'] . '/imp',
'icon' => '/horde2/imp/graphics/imp.gif',
'name' => _("Slackmail"),
'allow_guests' => true,
'status' => 'active',
'show' => true
);
The key lines above being 'name' and 'staus'.
As a measure of security I then disabled the test pages for IMP and Horde as they let on important server information to the world at large:
chmod o-r,g-r /usr/share/horde2/test.php
chmod o-r,g-r /usr/share/horde2/imp/test.php
Authors: Mike Harris, Psand.net
Version: $Revision: 1.1 $ (updated $Date: 2005/03/12 17:25:36 $)

Article copyright (c) 2004 Psand Limited. 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 included in the section entitled "GNU Free Documentation License".