MAC OS X, Linux, Windows and other IT Tips and Tricks

20 Jul 15 Relay emails for specific destinations

In the last couple of years many large email providers have started to refuse emails coming from certain IP addresses or according to certain other criteria. It is difficult to know for what reason certain emails are refused access with the server answer:
....refused to talk to me: 554....
The list of these emails destinations(which is growing by the day) is for example:

Therefore one temporary solution(till I can fix the cause) is to relay the problematic emails via a relay email server which is more accepted.
Here is the Postfix settings that allows me to do that:
Added the following entry in /etc/postfix/
transport_maps = hash:/etc/postfix/transport
And in the file /etc/postfix/transport relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25 relay:[]:25

Note: Here obviously you need to replace for your own relay server.
Hash the file for postfix:
postmap /etc/postfix/transport
And reload Postfix:
service postfix reload

19 May 15 Installing DMARC filtering in Debian Wheezy

Principle: DMARC is a bit of a strange animal. It serves as a filter against SPAM but only according to the rules given by the owner of the domain sending emails. So, for example, if I send emails as sender using a mail client program via my mail server , in order that my mails be seen as ‘good’ mail, I need to set-up the SPF and DKIM and DMARC TXT records in the DNS of the domain This way the receiving server will verify the validity of the SPF and DKIM of my domain and the using the DMARC record, decide what to do with the mails that fail the SPF or DKIM validation. In other words I instruct the receiving server what to do(and how) with emails that try to personify me sending emails. Of course the receiving server needs to have the DMARC vadidation mechanism installed to read my DNS DMARC record and act on the validation results.
This article provides instructions on how to install this mechanism only.
Installing DKIM(needed on the sending and receiving servers) is covered in this article:
I don’t cover the SPF here since there are a lot of info on the Internet which covers it.


Install the needed libraries:
apt-get install libmilter-dev
Check out the latest version of opendmarc in Source forge and use the link to download it:
eg. For version 1.3.1 you run the command:
wget //
tar xfvz opendmarc-1.3.1.tar.gz
cd opendmarc-1.3.1
./configure --prefix=/usr --with-spf --enable-live-tests
make && make install

Prepare the system user etc.
adduser --quiet --system --group --home /var/run/opendmarc opendmarc
chown opendmarc:opendmarc /var/run/opendmarc

Enter the sender host names that should be ignored by the filter
mkdir /etc/opendmarc/
echo -e "localshost\\\" > /etc/opendmarc/ignore.hosts

Edit the configuration file
vi /etc/opendmarc/opendmarc.conf
Set the parameters accordingly and issue the following command to get a short overview of the configuration:
grep -v '#' /etc/opendmarc.conf | egrep -v '^ *$'
For example content of my configuration file(/etc/opendmarc.conf):
AuthservIDWithJobID true
BaseDirectory /var/run/opendmarc
FailureReports true
FailureReportsOnNone true
HistoryFile /var/run/opendmarc/opendmarc.dat
IgnoreAuthenticatedClients true
IgnoreHosts /etc/opendmarc/ignore.hosts
PidFile /var/run/
RecordAllMessages false
ReportCommand /usr/sbin/sendmail -t
Socket inet:8893@localhost
SPFIgnoreResults true
SPFSelfValidate true
Syslog true
UserID opendmarc

The data files must be now created incl. access rights:
mkdir -p /var/run/opendmarc/
touch /var/run/opendmarc/opendmarc.dat
chown opendmarc.opendmarc /var/run/opendmarc/opendmarc.dat
chmod 600 /var/run/opendmarc/opendmarc.dat

Prepare the init start/stop script
cd /etc/init.d
cp skeleton opendmarc
chmod 755 opendmarc
vim opendmarc

Adapt the following parameters as appropriate to your settings:
# Provides: opendmarc
# Required-Start: $syslog
# Required-Stop: $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: opendmarc milter init script
# Description: Start stop of opendmarc postfix milter
# Please remove the "Author" lines above and replace them
# with your own name if you copy and modify this script.
# Do NOT "set -e"
# PATH should only include /usr/* if it runs after the script
DESC="OpenDMARC milter"
DAEMON_ARGS="-c /etc/opendmarc/opendmarc.conf -u opendmarc"

And in the same file in function do_stop():
#start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
killall opendmarc
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
#start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
killall opendmarc
[ "$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
[ "$?" = 2 ] && return 2
# Many daemons don't delete their pidfiles when they exit.
rm -f $PIDFILE
return "$RETVAL"

Save the file.
Check the opendmarc configuration file:
opendmarc -c /etc/opendmarc/opendmarc.conf -u opendmarc -n && echo OK
If all OK then start the service:
service opendmarc start

Postfix configuration:
Edit /etc/postfix/ and add the following lines. If already existing because of openDKIM, then simply add the missing parameters as follows:
smtpd_milters = inet:, inet:localhost:8893
non_smtpd_milters = inet:, inet:localhost:8893

Restart postfix
service postfix restart

07 May 15 Anti-SPAM mail filtering using SPF on Debian Wheezy

Install the package:
apt-get install postfix-policyd-spf-perl
Add this line to /etc/postfix/
policy-spf_time_limit = 3600s
Add the following lines to /etc/postfix/
policy-spf unix - n n - - spawn
user=policyd-spf argv=/usr/sbin/postfix-policyd-spf-perl

In /etc/postfix/, find the smtpd_recipient_restrictions section, and, immediately after permit_mynetworks (and permit_sasl_authenticated, if you’re using that), add:
check_policy_service unix:private/policy-spf,
Restart Postfix and check your logs to see if everything is working properly.
tail -f /var/log/mail.log

07 May 15 TCP Load balancing email/web servers with NginX

I’ve got 2 synchronized email servers running and, in order to make sure I don’t have to change the servername settings of my mail client in case one server goes down, I was looking for a straight TCP layer load balancer. There are a few software packages on the market that can do that , eg. Lvs-kiss etc. I found the solution of using NginX quite interesting, since the load balancing seems to be better built especially regarding the return route which gave me some headaches with LVS-KISS. Here is an example of using NginX and TCP load balancing to 2 IMAPs/SMTPs/Webmail servers.

Note: Unfortunately my IMAPs/SMTPs servers are using a legitimate certificates but because the email clients do use the address of an extra server for Loadbalancing, the certificate is declared invalid by the email clients. This TCP load balancing operates at a lower layer(TCP) than application layer where SSL certificates can be used to authenticate. It is therefore not possible to add a certificate to this load balancer. For this reason it is recommended to use a wildcard certificate in both back-end Mail servers for production use of Mail services load-balancing. For HTTP and HTTPS there is no need for a wildcard certificate. Normal certificates installed in both web servers will do.

NginX shortcomings

NginX did have the TCP load-balancing feature compiled only in the Pro version with all the features of backend health check etc.
Since the version 1.9 they introduced a limited version of the TCP load-balancing feature into the community version.
Unfortunately if you need other pro features like backend health-checks you are out of luck.
Fortunately some 3rd parties have created a patch for earlier versions which implement the necessary features of a good low level TCP load balancer. In this tutorial I will show how to compile and patch an earlier version of Nginx to achieve the TCP Load-balancer.


Login as root and run the following commands:
apt-get remove nginx
apt-get install libssl-dev build-essential git
mkdir ~/build ; cd ~/build
wget -O - // | tar xfvz -
git clone git://
cd nginx-1.6.2/
patch -p1 < ../nginx_tcp_proxy_module/tcp.patch ./configure --add-module=../nginx_tcp_proxy_module --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module --without-http_rewrite_module --without-http_charset_module --without-http_gzip_module --without-http_ssi_module --without-http_userid_module --without-http_access_module --without-http_auth_basic_module --without-http_autoindex_module --without-http_geo_module --without-http_map_module --without-http_split_clients_module --without-http_referer_module --without-http_proxy_module --without-http_fastcgi_module --without-http_uwsgi_module --without-http_scgi_module --without-http_memcached_module --without-http_limit_conn_module --without-http_limit_req_module --without-http_empty_gif_module --without-http_browser_module --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/ --http-client-body-temp-path=/var/lib/nginx/body make && make install mkdir -p /usr/share/nginx/logs mkdir /var/log/nginx mkdir -p /var/lib/nginx/body touch /var/log/nginx/error.log /var/log/nginx/access.log touch /usr/share/nginx/logs/tcp_access.log chown -R www-data: /var/{lib,log}/nginx /usr/share/nginx/logs

Check it's version:
/usr/share/nginx/sbin/nginx -V
Create an init start/stop script
touch /etc/init.d/nginx
chmod 755 /etc/init.d/nginx
mcedit /etc/init.d/nginx

# Provides: nginx
# Required-Start: $local_fs $remote_fs $network $syslog
# Required-Stop: $local_fs $remote_fs $network $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts the nginx web server
# Description: starts nginx using start-stop-daemon
# Include nginx defaults if available
if [ -f /etc/default/nginx ]; then
. /etc/default/nginx
test -x $DAEMON || exit 0
set -e
. /lib/lsb/init-functions
test_nginx_config() {
if $DAEMON -t $DAEMON_OPTS >/dev/null 2>&1; then
return 0
return $?
case "$1" in
echo -n "Starting $DESC: "
# Check if the ULIMIT is set in /etc/default/nginx
if [ -n "$ULIMIT" ]; then
# Set the ulimits
ulimit $ULIMIT
start-stop-daemon --start --quiet --pidfile /var/run/$ \
--exec $DAEMON -- $DAEMON_OPTS || true
echo "$NAME."
echo -n "Stopping $DESC: "
start-stop-daemon --stop --quiet --pidfile /var/run/$ \
--exec $DAEMON || true
echo "$NAME."
echo -n "Restarting $DESC: "
start-stop-daemon --stop --quiet --pidfile \
/var/run/$ --exec $DAEMON || true
sleep 1
# Check if the ULIMIT is set in /etc/default/nginx
if [ -n "$ULIMIT" ]; then
# Set the ulimits
ulimit $ULIMIT
start-stop-daemon --start --quiet --pidfile \
/var/run/$ --exec $DAEMON -- $DAEMON_OPTS || true
echo "$NAME."
echo -n "Reloading $DESC configuration: "
start-stop-daemon --stop --signal HUP --quiet --pidfile /var/run/$ \
--exec $DAEMON || true
echo "$NAME."
echo -n "Testing $DESC configuration: "
if test_nginx_config; then
echo "$NAME."
exit $?
status_of_proc -p /var/run/$ "$DAEMON" nginx && exit 0 || exit $?
echo "Usage: $NAME {start|stop|restart|reload|force-reload|status|configtest}" >&2
exit 1
exit 0

The NGinX configuration here TCP-load-balances the following ports: 143, 993, 587, 465, 80 & 443.

To use only the TCP load balancing feature of NginX we configure the strict minimum:
Rename the created configuration file
mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig
Create the new configuration file with the following content:
mcedit /etc/nginx/nginx.conf
user www-data;
worker_processes 1;
events {
worker_connections 1024;
# ---------- TCP Load balancer for IMAPs, IMAP and SMTPS -----------------
tcp {
# ----------------- IMAPs ------------------
upstream cluster_imaps {
check interval=5000 rise=2 fall=5 timeout=2000 type=tcp;
server {
listen 993;
proxy_pass cluster_imaps;
# ----------------- IMAP -------------------
upstream cluster_imap {
check interval=5000 rise=2 fall=5 timeout=2000 type=imap;
server {
listen 143;
proxy_pass cluster_imap;
# ----------------- SMTP -------------------
upstream cluster_smtp {
check interval=5000 rise=2 fall=5 timeout=2000 type=smtp;
server {
listen 587;
proxy_pass cluster_smtp;
# ----------------- SMTP -------------------
upstream cluster_smtps {
check interval=5000 rise=2 fall=5 timeout=2000 type=smtp;
server {
listen 465;
proxy_pass cluster_smtps;
# ----------------- HTTP -------------------
upstream cluster_http {
check interval=5000 rise=2 fall=5 timeout=2000 type=tcp;
server {
listen 80;
proxy_pass cluster_http;
# ----------------- HTTPS -------------------
upstream cluster_https {
check interval=5000 rise=2 fall=5 timeout=2000 type=tcp;
server {
listen 443;
proxy_pass cluster_https;
#--------------- End of TCP Block --------------

Start NginX server:
service nginx start

Some explanations of this NginX configuration

interval=2000 # Alive-Check interval for the back-end mail servers, 2s
rise=2 # How many Alive-Checks must be successful in order to consider the server as ON-line
fall=5 # How many Alive-Checks must fail in order to consider the server as OFF-line
timeout=1000 # Timeout for responses of Alive-Checks Here: 1 sec.
type=imap; # Type of Alive-Check

STICKY Sessions
ip_hash; # Based on client IP

An overview of types from NGinX Git repositories:
1. tcp is a simple tcp socket connect and peek one byte.
2. ssl_hello sends a client ssl hello packet and receives the server ssl hello packet.
3. http sends a http request packet, receives and parses the http response to diagnose if the upstream server is alive.
4. smtp sends a smtp request packet, receives and parses the smtp response to diagnose if the upstream server is alive. The response begins with ‘2’ should be an OK response.
5. mysql connects to the mysql server, receives the greeting response to diagnose if the upstream server is alive.
6. pop3 receives and parses the pop3 response to diagnose if the upstream server is alive. The response begins with ‘+’ should be an OK response.
7. imap connects to the imap server, receives the greeting response to diagnose if the upstream server is alive.

19 Mar 14 Archiving all incoming/outgoing mails using Sieve

The following custom Sieve script can be used to make a copy of every email a user sends or receives.
In the example, the user is and the copy of the .MSG file is saved in the spyfolder directory.
if envelope :contains ["from","to"] "" { fileinto "c:\\spyfolder"; keep; }
Note: Be careful to monitor the size of the spyfolder as the message files could accumulate and fill the disk drive!

19 Mar 14 Blocking user to send sensitive information using Sieve

The following article uses examples to show how to block users from sending attachments containing sensitive information (e.g. financial information) to the outside world. The script blocks attachments with certain names by flagging particular words.

– Your domain is
– The administrator wants to block attachments with the word customer in the filename only if it is outbound (not to the local domain)
– The administrator also wants to block attachments with the word legal

Sieve Script:
Blocking ‘customer’ in attached filename:
if not envelope :contains "to" "" {
if attachment :matches "*customer*" { discard; stop; }

Blocking ‘customer’ and ‘legal’ in attached filename:
if not envelope :contains "to" "" {
if attachment :matches ["*customer*","*legal*"] { discard; stop; }

19 Mar 14 Force sending mails using SSL/TLS

In some cases it might be requested to transfer emails to another mail server using encryption (SSL/TLS).
Here is a way to do it using Sieve language which Dovecot supports:

Use a sieve script to conditionally send encrypted messages.
The script would insert a header element, called X-Requires-SSL, prompting SMTPDS (the Delivery Service) to attempt to connect to the destination using STARTTLS. If the destination does not support this, the sender receives a bounce to this effect (“destination does not support STARTTLS”).

The form of the script is as follows:
require ["editheader","variables"];
if {
addheader "X-Requires-SSL" "true";

E.g. force encryption if the word encrypt appears in the subject line:
if header :contains "subject" "encrypt" {
addheader "X-Requires-SSL" "true";

Requirements for this to work:
– Your server requires an SSL certificate
– This certificate must be configured in the Modus Console
– SMTP Encryption(TLS) must be supported

20 Jan 14 Creating a XEN machine and Installing Group Office in Debian Wheezy


In this Tutorial I will explain the steps I did to create a Xen Virtual Machine with minimal packages and then install the latest Group Office Web based Collaboration software. You’ll need to be fluent in Linux and Xen because I don’t explain much here.

Note: My hypervisor is Xen 4.0 in Debian Squeeze with xen-utils-4.0 package installed. I also use fictive domain( names and IP addresses just as example.

Creating the Xen Virtual Machine

This virtual machine will be created with the xen tools which bootstraps the creation of the VM.
mkdir -p /virtual/xen/
cd /virtual/xen/
xen-create-image --dir=. --dist=wheezy --size=20Gb --swap=2048Mb --ip= --gateway= --netmask= --memory=4096Mb --arch=amd64 --role=udev

Install the kernel and pyGrub
– Put the produced disk.img and swap.img in the proper path.
eg. in /virtual/xen/MAIL/
Mount the disk image in loop
mkdir /mnt/MAIL
mount /virtual/xen/MAIL/disk.img /mnt/MAIL -o loop,rw

Mount /sys, /proc, /dev and chroot to it
mount /proc /mnt/MAIL/proc -o bind
mount /sys /mnt/MAIL/sys -o bind
mount /dev /mnt/MAIL/dev -o bind
chroot /mnt/MAIL

Install the grub-legacy in VM
apt-get update
apt-get install grub-legacy linux-image-3.2.0-4-amd64 mc
mkdir /boot/grub
mcedit /boot/grub/menu.lst
default 0
timeout 2
title Debian GNU/Linux
root (hd0,0)
kernel /vmlinuz root=/dev/xvda1 ro
initrd /initrd.img
title Debian GNU/Linux (recovery mode)
root (hd0,0)
kernel /vmlinuz root=/dev/xvda1 ro single
initrd /initrd.img

Leave chroot and unmount all.
umount /mnt/MAIL/dev
umount /mnt/MAIL/sys
umount /mnt/MAIL/proc
umount /mnt/MAIL/

Adjust the VM xen configuration(/etc/xen/ as follows:
Replace the older kernel and initrd lines in the Xen DOMu configuration file as follows:
kernel = '/boot/vmlinuz-2.6.32-5-xen-amd64'
ramdisk = '/boot/initrd.img-2.6.32-5-xen-amd64'
bootloader = '/usr/lib/xen-default/bin/pygrub'

Adjust the paths of the disks properly:
disk = [

Test the pyGRUB configuration with the VM disk
Note: A GRUB menu should appear for a few seconds and then disappear with an error message. Ignore the error message. Most important is that the Grub menu appears.
/usr/lib/xen-default/bin/pygrub /virtual/xen/MAIL/disk.img
Start the VM
The Grub menu should appear and start booting.
xm create /etc/xen/ -c

Installing Group-Office

Login as root and configure APT with the Group Office repositories
(REF: //
apt-get update, apt-get upgrade
echo -e "\n## Group-Office repository\ndeb // fivezero main" | tee -a /etc/apt/sources.list
gpg --keyserver hkp:// --recv-keys 01F1AE44
gpg --export --armor 01F1AE44 | apt-key add -
apt-get update

Install Group Office
apt-get install groupoffice-mailserver postfix postfix-mysql dovecot-mysql dovecot-managesieved dovecot-sieve dovecot-lmtpd rsync mc
– Setting root password to MySQL server.
– Setting the domain name.

Note from Group Office before start of installation.
After installation is completed launch your browser and go to //localhost/groupoffice/
or replace localhost with the hostname / IP of this machine.
The default login is username: admin and password: admin.
Enjoy Group-Office!

Setting root password to MySQL server:
Setting MySQL password of user:groupoffice-com DB groupofficecom :

Now some undesired installation features messages will appear:

[FAIL] Clamav signatures not found in /var/lib/clamav ... failed!
[FAIL] Please retrieve them using freshclam ... failed!
[FAIL] Then run '/etc/init.d/clamav-daemon start' ... failed!

To fix that:
apt-get -f install
/etc/init.d/clamav-daemon start

All looking good now,
In Browser, try to login with your ‘admin’ password at:

HINT about domains:
If you configure more domains in the admin web interface under ‘Email Domains’ menu item and try to create new users, only the original domain is offered to select as possible mailboxes for the new users. The newly configured domains are not listed. To remedy to that, you need to enter all of the domains this system may use into both GroupOffice and Amavis the configuration file:
IN /etc/groupoffice/config.php

IN /etc/amavis/conf.d/05-domain_id
@local_domains_acl = ( ".$mydomain" , "", "")

In order to raise your mail server’s general acceptance from large mailing servers like AOL, GMX, Yahoo, etc. it is recommended to:
– Configure your domain in DNS concerning the SPF1 and SPF2
– Configure in your mail server and DNS to send DKIM token.
See DKIM installation at: // for DKIM installation.
– Configure Postfix to use RBL SPAM filtering(see instructions below)

SPAM Reduction

This server is already providing some anti-spam protection but in some cases extra filter might need to be installed.

Add some more RBL SPAM Filtering

Note: In my mail server, almost every day about 800 to 2000 Spams are blocked using the RBL filtering method. So I do recommend it since its also quite simple as well.
Edit your Postfix main configuration file /etc/postfix/ and replace the existing configuration with the following one. It contains the same configuration as the original except it adds to the list of RBL servers.
Postfix RBL settings:
smtpd_recipient_restrictions =
check_recipient_access hash:/etc/postfix/spam_rec_addr,
check_client_access hash:/etc/postfix/rbl_whitelist,

# Allows to add a SPAM blacklist if needed (/etc/postfix/spam_addr)
smtpd_reject_unlisted_sender = yes
smtpd_sender_restrictions =
check_sender_access hash:/etc/postfix/spam_addr

# Allows to set regex rules to refuse certain know SPAM content in (/etc/postfix/spam_body_regex)
body_checks = regexp:/etc/postfix/spam_body_regex

Raising server delivery acceptance rate with DKIM

Ref: See instruction in //

Raising security with TLS mail delivery

Ref: //
This feature allows postfix to send emails to remote mail servers using TLS encryption if the remote email server does support TLS transport otherwise clear text as usual.

Edit the file: /etc/postfix/ and at the end enter the following:
smtp_tls_security_level = may

OPTIONAL: Enable DKIM verification in Amavis

This verification will warn you if a mail has been received which failed the DKIM verification.
Edit the file /etc/amavis/conf.d/60-groupoffice_defaults
Add the following line:
# Activating warnings for failed DKIM checked emails
$enable_dkim_verification = 1;

OPTIONAL: Enable the addition of ‘*****SPAM*****’ in header of suspicious emails.

Edit the file: /etc/amavis/conf.d/60-groupoffice_defaults
Add the following line:
$sa_spam_subject_tag = '***SPAM*** ';
You can then use this extra Subject tag to filter your mails and send them automatically in another directory like in ‘Spam’ directory.

OPTIONAL: Enable the Bayes Spam and Ham learning

For this we need to feed Spamassassin some Spam(Bad) and Ham(good) emails.
In this above configuration file the path of the files where Spamassassin learns is set to /home/spamd which doesn’t exist.
I don’t quite know how SA will discern the difference between Ham and spam So I’m doing it another way.
In order to feed it some spam mails each user should contribute to it as follows:
– The users create two new mail folder called exactly ‘Spam’ and ‘Ok’
– Then each time the user receives a definite SPAM email that is NOT tagged *****SPAM*****, he drops the email into his ‘Spam’ folder and forget about it.
– Each time he sees that a good mail has been erroneously tagged *****SPAM***** he drops a COPY a copy of the email into his ‘Ok’ folder and forgets about it.
The following configurations will ensure the following:
– The emails gathered in user’s ‘Spam’ and ‘Ok’ directories will be harvested by a cron job and be added automatically to /home/SA/spam(BAD) or /home/SA/ham(Good) directories respectively for sa-learn to learn from them.

We will create the directories and assign full access to the user ‘spamd’
mkdir -p /home/SA/spam
mkdir -p /home/SA/ham
chown spamd: /home/SA/spam /home/SA/ham

– SpamAssassin will regularly learn from it and offer a continuous increasing accuracy in detecting spams.
System cron job to harvest each day the user’s Spam mails and feed SA learning directory:
0 0 * * * /root/bin/

Creating the script:
touch /root/bin/
chmod 755 /root/bin/
Content of script /root/bin/
# make sure the lock file can be written in /home/spamd/
mkdir -p /home/spamd
chown -R spamd: /home/spamd
# Purpose: Feeds SA to learn the SPAM emails and GOOD emails
# Harvest the SPAM emails from users and deposit them in spam directory
for spamdir in $(find /home/vmail/ -type d -name '.Spam') ; do rsync -au $spamdir/cur/ /home/SA/spam/; done
# Harvest the HAM emails from users and deposit them in ham directory
for hamdir in $(find /home/vmail/ -type d -name '.Ham') ; do rsync -au $hamdir/cur/ /home/SA/ham/; done
# Now tell SA to learn from them
/usr/bin/sa-learn --spam -u spamd --dir /home/SA/spam/* -D
/usr/bin/sa-learn --ham -u spamd --dir /home/SA/ham/* -D
# Then deleted the mails it learned from to prevent relearning the same thing and accumulating old mails
rm -r /home/SA/spam/* /home/SA/ham/*
# We let the users delete their own spam and ham mails.
# eof

IMPORTANT: In order for the spam filtering/Dovecot sieve to work you have to make sure that the following line is disabled or not present in /etc/postfix/
#transport_maps = proxy:mysql:/etc/postfix/
If present and enabled this above line overwrites the setting of transport agent and prevents postfix from using ‘dovecot’ as local transport by using ‘virtual’ instead. It’s been fixed in the GroupOffice version 5.0.44.

Enabling DNS White List (DNSWL) in Postfix

Resources: // provides a Whitelist of known legitimate email servers to reduce the chances of false positives while spam filtering. To enable it edit the file /etc/postfix/ and add the following line right before the postgrey line as follows:
smtpd_recipient_restrictions =
(postgrey line below)
check_policy_service inet:,

To force using TLS for delivering to selected destinations and fail sending the mail if the destination server doesn’t support it.
smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
Content of /etc/postfix/tls_policy encrypt encrypt

Hash the list:
postmap /etc/postfix/tls_policy

Allowing roaming SMTP use with SASL authentication

NOTE: Because the users’ credentials are stored in GroupOffice MySQL database we need to do the special authentication chain via dovecot which is configured to read Group Office database and its users data:
Configure SASL authentication
postconf -e 'smtpd_sasl_auth_enable = yes'
postconf -e 'smtpd_sasl_security_options = noanonymous'
postconf -e 'broken_sasl_auth_clients = yes'
postconf -e 'smtpd_sasl_type = dovecot'
postconf -e 'smtpd_sasl_path = private/auth'

Edit the file /etc/dovecot/conf.d/10-master.conf and enter inside the section ‘service auth {‘ insert the following lines as follows:

# Postfix smtp-auth
unix_listener /var/spool/postfix/private/auth {
mode = 0666
user = postfix
group = postfix

PROBLEM: After I upgraded GroupOffice to version 5.0.55 I was no more capable to login my mail accounts.
See solution in //
The /var/log/mail.log said:
..... inbox=yes namespace missing
The solution is:
Edit the file /etc/dovecot/conf.d/15-mailboxes.conf and right under the line:
namespace inbox {
Insert the line

Raising the SMTP security with TLS encryption

This generates a self-signed certificate. It is strongly recommended to buy a proper CA signed certificate for that purpose especially if your mail clients are not very computer literates. The security warning messages appearing in their mail clients because of self-signed certificates might scare them and lose trust in your service.
Generating the self-signed certificate:
mkdir -p /etc/ssl/mailserver/
cd /etc/ssl/mailserver/
openssl genrsa 1024 > mail-key.pem
chmod 400 mail-key.pem
openssl req -new -x509 -nodes -sha1 -days 365 -key mail-key.pem > mail-cert.pem

Enter the information required for the self signed certificate.
IMPORTANT: Enter your host name when ‘Common Name’ is asked.
Configuring postfix for TLS
Run the commands:
postconf -e 'smtpd_use_tls = yes'
postconf -e 'smtpd_tls_session_cache_timeout = 3600s'
postconf -e 'smtpd_tls_cert_file = /etc/ssl/mailserver/mail-cert.pem'
postconf -e 'smtpd_tls_key_file = /etc/ssl/mailserver/mail-key.pem'
postconf -e 'smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache'
postconf -e 'smtpd_tls_security_level = may'
postconf -e 'smtpd_tls_loglevel = 0'
postconf -e 'tls_random_source = dev:/dev/urandom'
postconf -e '#smtpd_tls_CAfile = /etc/postfix/cert/cacert.pem'

IMPORTANT NOTE: The intermediate CA and Key of certificate MUST be included in the certificate file (CRT) if you dont specify it in smtpd_tls_CAfile and smtpd_tls_key_file.

You must also make sure the “permit_sasl_authenticated” is present in the “smtpd_recipient_restrictions” configuration option. Edit this option in /etc/postfix/ and add it right after “permit_mynetworks”.

Edit the file /etc/postfix/ and add the following lines:
# Added to allow postfix to also listen to port 587(submission) well as port 465(smtps)
587 inet n - - - - smtpd
465 inet n - - - - smtpd

Adding extra postfix server security

Recommendation for better security by OpenVAS
postconf -e 'disable_vrfy_command=yes'

Restart postfix and dovecot

/etc/init.d/postfix restart
/etc/init.d/dovecot restart

APACHE2 Configuration

Configuring Redirection of ALL HTTP requests to HTTPS

a2enmod ssl rewrite
a2ensite default-ssl

Edit the file: /etc/apache2/sites-available/default-ssl
and add the following lines at the very end after </IfModule>.
# Redirecting all HTTP to HTTPs
<IfModule mod_rewrite.c>
<IfModule mod_ssl.c>
RewriteEngine on
RewriteCond %{HTTPS} !^on$ [NC]
RewriteRule . //%{HTTP_HOST}%{REQUEST_URI} [L]

Edit the file: /etc/apache2/sites-available/default
and add the following lines after LogLevel warn.
# Redirecting all HTTP to HTTPs
<IfModule mod_rewrite.c>
<IfModule mod_ssl.c>
RewriteEngine on
RewriteCond %{HTTPS} !^on$ [NC]
RewriteRule . //%{HTTP_HOST}%{REQUEST_URI} [L]

Installing separate WebMail Interfaces

Configuration of RoundCube and Apache

Install Roundcube WebMail interface
apt-get install roundcube roundcube-plugins roundcube-plugins-extra
Prepare configuration for Roundcube and Apache
Edit file: /etc/roundcube/apache.conf
Uncomment the following 2 lines as follows:
Alias /roundcube/program/js/tiny_mce/ /usr/share/tinymce/www/
Alias /roundcube /var/lib/roundcube

Configuration of Squirrelmail and Apache

Installing Squirrelmail WebMail interface
apt-get install squirrelmail squirrelmail-decode
ln -s /etc/squirrelmail/apache.conf /etc/apache2/conf.d/squirrelmail

For changing configuration of squirrelmail, run the command:

ADD authentication security to admin sites

Edit the file /etc/apache2/sites-available/default-ssl
and add the following lines at the very end:
# Authentication for private areas
<LocationMatch (/awstats|/awstats-icon|/mailgraph|/queuegraph|/phpmyadmin)>
AuthName "Private Area"
AuthType Basic
AuthUserFile /etc/apache2/web.auth
Require valid-user

touch /etc/apache2/web.auth
For each admin user you need to create a password with this command
htpasswd /etc/apache2/web.auth <username>

Installing AWSTATS, MAILGRAPH and QUEUEGRAPH for Mail stats

As default Awstats creates a full new report at: 03:10 Hrs each day
it also refreshes the data every 10 minutes.

apt-get install awstats mailgraph queuegraph
chown www-data. /var/lib/awstats
chmod o+r /var/log/mail.log

Edit /etc/awstats/awstats.local
Add the following lines:
# You can overrides config directives here.
# This is particularly useful for users with several configs for
# different virtual servers, who want to reuse common parameters.
# Also, this file is not updated with each new upstream release.
LogFile="perl /usr/share/doc/awstats/examples/ standard < /var/log/mail.log |"
LogFormat="%time2 %email %email_r %host %host_r %method %url %code %bytesd"

Create the a Apache configuration file: /etc/apache2/conf.d/awstats
and add this following content:
# Configuration for email-AWSTATS, MAILGRAPH and QUEUEGRAPH
Alias /awstats /usr/lib/cgi-bin/
Alias /awstats-icon/ /usr/share/awstats/icon/
Alias /mailgraph /usr/lib/cgi-bin/mailgraph.cgi
Alias /queuegraph /usr/lib/cgi-bin/queuegraph.cgi
Alias /queuegraph.cgi /usr/lib/cgi-bin/queuegraph.cgi
<Directory /usr/lib/cgi-bin/>
Options +execCGI
AddHandler cgi-script .pl .cgi

Restart Apache service

service apache2 restart

List of URLs for this mail server:

Group Office //
Roundcube Webmail //
Squirrelmail Webmail //
Mail stats(Awstats) //
Mail traffic graph //
Mail queues graph //

Group Office forum and wikis addresses


01 Apr 13 Install Geotrust/RapidSSL certificate in Zimbra 8.0.x

This How-to is based on the following page and after failing to install myself my commercial certificate I feel very grateful for his contribution:

The best way to install a RapidSSL cert is via the CLI as the root user.

1. Start by logging as root superuser into your Zimbra servers CLI via SSH.

2. As root begin by generating a Certificate Signing Request (CSR).
Below replace ‘’ with the FQDN of your Zimbra server.
/opt/zimbra/bin/zmcertmgr createcsr comm -new -keysize 2048 -subject "/C=GB/ST=England/L=London/O=Company Name/OU=Company Branch Name/" -subjectAltNames
The above command includes the following codes:
/C = Country: The Country is a two-digit code — for the United Kingdom, it’s ‘GB’. A list of country codes is available here –
/ST = State: State is a full name, i.e. ‘California’, ‘Scotland’.
/L = Locality: Locality is a full name, i.e. ‘London’, ‘New York’.
/O = Organization: The Organization Name is your Full Legal Company or Personal Name, as legally registered in your locality.
/OU = Organizational Unit: The Organizational Unit is whichever branch of your company is ordering the certificate such as accounting, marketing, etc.
/CN = Common Name: The Common Name is the Fully Qualified Domain Name (FQDN) for which you are requesting the ssl certificate.
This will be the FQDN of your Zimbra server, e.g. or

3. Now upload/send the certificate request to your SSL provider.
(Zimbra saves it to /opt/zimbra/ssl/zimbra/commercial/commercial.csr)
They will most likely provide you with your Commercial Certificate via an email in the form of text or an attached file.

Note:If you already have your commercial certificate you only need to start at step 4 below.

4. Save your Commercial Certificate in a temporary file. If provided as plain text you can cut and paste it into a new file using nano:
nano /tmp/commercial.crt
5. Download and save the root Certificate Authority (CA) for RapidSSL certificates to a temporary file. (e.g. /tmp/ca.crt).
Again you can cut and paste the following GeoTrust root CA text into a new file using nano.

nano /tmp/ca.crt
The root CA for RapidSSL certificates is provided by GeoTrust and can also be found here

6. Download any intermediary CAs from your SSL provider, again to a temporary file.
(e.g. /tmp/ca_intermediary.crt). RapidSSL certs usually come with a single intermediary certificate.
Once again, cut and paste the follwong RapidSSL Intermediate certificate using nano

nano /tmp/ca_intermediate.crt
7. Combine root and intermediary CAs into a temporary file.
cat /tmp/ca.crt /tmp/ca_intermediate.crt > /tmp/ca_chain.crt
8. Copy your private key created for the certificate into
9. Deploy your commercial certificate to Zimbra
/opt/zimbra/bin/zmcertmgr deploycrt comm /tmp/commercial.crt /tmp/ca_chain.crt
10. To finish, verify the certificate was deployed.
/opt/zimbra/bin/zmcertmgr viewdeployedcrt
11. Restarting Zimbra services will ensure the new commercial certificate takes effect.
su zimbra
zmcontrol restart

Your commercial certificate is now installed for Zimbra 8.0.x

15 Mar 13 Installing OpenDKIM in Debian Squeeze/Wheezy

Lately my mail server started to get refusals of emails from large mailing systems like AOL, Yahoo etc.
I can’t blame them for trying to minimize the SPAMS to their clients.
Although using an approved relay service is a good solution,
if you want to take care of it yourself here is OpenDKIM at the rescue.

The mail server sends an email with an individual domain key in the mail header. The receiving server checks the key in the header against the one in the DNS record of the sender’s domain. If they match the email is seen as legitimate email.

These instructions are inspired from the helpful site // and expanded with a script. They relate only to the installation of the standard Debian Squeeze version.

Installation of DKIM
The standard Debian Squeeze version of openDKIM is about 2 years old but works well. If you want to install the latest version though you could get it from compile it yourself at //

1.Install the Debian Squeeze openDKIM package
apt-get install opendkim
or if in Debian Wheezy
1.Install the Debian Wheezy openDKIM and its tools package
apt-get install opendkim opendkim-tools

2. Edit /etc/opendkim.conf
KeyTable /etc/opendkim/KeyTable
SigningTable /etc/opendkim/SigningTable
ExternalIgnoreList /etc/opendkim/TrustedHosts
InternalHosts /etc/opendkim/TrustedHosts
# Optional - To show more information in logs
LogWhy yes

3. Create the config directories and files
mkdir -p /etc/opendkim/keys
touch /etc/opendkim/KeyTable
touch /etc/opendkim/SigningTable
touch /etc/opendkim/TrustedHosts

4. Edit /etc/opendkim/TrustedHosts
Note: Here you enter all domains, hostnames and/or ip’s / Subnets that should be handled by OpenDKIM.
Don’t forget localhost.
Content example:

5. Edit /etc/default/opendkim
Uncomment this line:
SOCKET="inet:12345@localhost" # listen on loopback on port 12345

6. Edit /etc/postfix/
Add the following lines
milter_default_action = accept
milter_protocol = 6
smtpd_milters = inet:
non_smtpd_milters = inet:

Note: In the above configuration I use instead of ‘localhost’ to prevent the following warning in the logs.
warning: connect to Milter service inet:localhost:12345: Connection refused
The reason being that in Wheezy Postfix sees the IPv4 and IPv6 of ‘localhost’ and tries 2 times in which the try at IPv6 fails with this warning.

6. Edit /etc/postfix/
Add the following option ‘,no_milters‘ at the end of the line: eg. inet n - n - - smtpd
# .... Here I didn't show all the options which are irrelevant for this issue.....
-o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_milters

7. Generating individual domain keys and configuring OpenDKIM for per domain.
I order for Postfix/OpenDKIM to send/verify a key in each email’s header for which DKIM should be used, the following needs to be done per domain:
– Create a domain private key and configure OpenDKIM so it adds(outgoing) or verify the key(incoming) in the email’s header.
– Generate a domain key and add it to the Free-Text DNS record of the domain.

Here you have 2 choices:
– The easy method(using a script like the one below)
– The hard method(Manually)

The easy method

1. Run this script which generates the DKIM Key and configures OpenDKIM for each domain given.
Command: add_domains_opendkim <DomainName> [DomainName] [DomainName] …..
DomainName should be the root domain (without the www)

Script: /root/bin/add_domains_opendkim
# Authors: Pierre Burri-Wittke/Michel Bisson
# 9. March 2013
# Purpose: Generates DNS-Txt keys and configures OpenDKIM for one or multiple domains
# Verifying the entries
if [ "$#" -lt 1 ]; then
echo "ERROR: Wrong number of parameters"
echo "Usage: add_domains_opendkim [DomainName] ....."
echo "eg. add_domains_opendkim"
exit 1
# Checking if OpenDKIM is installed and if yes creating the necessary data directory
if ! [ -d /etc/opendkim ]; then
echo "ERROR: The package OpenDKIM is not installed. Install it and rerun this command."
exit 2
mkdir -p /etc/opendkim/keys
# Verifying the given domains and skip them if errors or already configured
for domain ; do
# Check the mail handling resolving
if ! (host $domain | grep -q 'is handled by'); then
echo "Domain $domain doesn't resolve well. Skipping"
echo "Output:"
host $domain
# Check if the domain is already configured in openDKIM
elif (grep -q "$domain default._domainkey.$domain" /etc/opendkim/SigningTable); then
echo "Domain $domain is already configured in /etc/opendkim/SigningTable. Skipping"
elif (grep -q "$domain default._domainkey.$domain" /etc/opendkim/KeyTable); then
echo "Domain $domain is already configured in /etc/opendkim/KeyTable. Skipping"
# All ok, then generate the key and configure OpenDKIM
mkdir /etc/opendkim/keys/$domain
echo " "
echo "Generate the keys..."
cd /etc/opendkim/keys/$domain
opendkim-genkey -r -d $domain
chown opendkim:opendkim default.private
ls -l /etc/opendkim/keys/$domain
echo " "
echo "Adding following lines in /etc/opendkim/KeyTable & /etc/opendkim/SigningTable"
echo " default._domainkey.$domain $domain:default:/etc/opendkim/keys/$domain/default.private"
echo "default._domainkey.$domain $domain:default:/etc/opendkim/keys/$domain/default.private" >> /etc/opendkim/KeyTable
echo " $domain default._domainkey.$domain"
echo "$domain default._domainkey.$domain" >> /etc/opendkim/SigningTable
echo " "
echo "-------------------- TODO ----------------------"
echo "Now copy the record below in your DNS (until the end of the domain! Do not include lines with '***')"
echo "DNS: Free Text Entries/freier Textentraege of domain "
echo " "
echo "*** $domain *** ---------------------------"
cat /etc/opendkim/keys/$domain/default.txt
echo "*** $domain *** ---------------------------"
# Restart OpenDKIM if at least one new domain was registered in OpenDKIM
echo " "
if $result ; then /etc/init.d/opendkim restart ; fi

Now the hard Method…Manual

1. Generate key
(example here with domain:
mkdir -p /etc/opendkim/keys/
cd /etc/opendkim/keys/
opendkim-genkey -r -d
chown opendkim:opendkim default.private

2. Add domain to KeyTable /etc/opendkim/KeyTable
nano /etc/opendkim/KeyTable
Add line:
3. Add domain to SigningTable /etc/opendkim/SigningTable
nano /etc/opendkim/SigningTable
Add line:
4. Display the DNS key
cat /etc/opendkim/keys/

Restarting OpenDKIM:
/etc/init.d/opendkim restart

Note: In OpenDKIM 2.0.1 domain names are case sensitive (supposed to be fixed from 2.3.1 but I have not tested).
This means that in the above example an email from will be signed, but an email from will not be signed.
The workaround is to add one extra entry for to SigningTable.

The DNS entry

Whether you are using the easy way (script) or the manual way you still have to enter the key in DNS manually for each domain.
This key, displayed by the above script or by the step 4 in manual mode, is a single line and looks like this:
default._domainkey IN TXT "v=DKIM1; g=*; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4....long hash.......PBODxsDCEJwHEyFpQIDAQAB" ; ----- DKIM default for mydomain.comYou need to enter the full line in a Free Text record of the domains DNS.

Note 1: Together with SPF authentication(// this should present a very good email authentication method.

Note 2: Although the OpenDKIM configuration file offers the possibility of authenticating sub domains senders(SubDomains yes), in this version it doesn’t seem to work at all. For example, when a mail is sent from a system user in the mail server, it will be identified as and not for which DKIM is configured. I don’t know if this feature is working in the newer versions though.

Verifying the DKIM DNS record

Example for the domain ‘’
dig TXT
;; ANSWER SECTION: 600 IN TXT "v=DKIM1\; k=rsa\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC/H98o5XmzkUtnvvtZ0+T64xsKNYsWXOXLi0xkQdqK0tq18CV0rZT1+uCqQmov/uoS/RgxE5omvNuzFJR8zt4WPHORGe+UeZr9h0q/eEntmIhx9Sg1vWREKeZcDw0sUMzZRMN0/GrjVdZYKH89vfJeL0awtqkQ4h8Sbonbwh3u2QIDAQAB"