Home Download FAQ / Knowledge Base Screenshots Documentation Support

Fighting spam with qpsmtpd

OK, so you want to use Citadel with a Postfix-based spam filter, but installing and configuring postfix is a beast. An alternative, and frankly a much better solution is to use qpsmtpd. From the wiki:

The qpsmtpd daemon is written in pure Perl and can be customized easily. It consists of a core that implements a complete SMTP server, and a number of plug-ins that enhance the operations of the server. These plug-ins allow for the checking of recipients and senders, as well as virus scanning, spam checking, blocking lists (DNS and RHS), SMTP AUTH and TLS.

Is it ready for a production server? Apache::Qpsmtpd embeds qpsmtpd in an Apache 2 server with mod_perl 2. This method is used by apache.org to handle over 2 million messages per day. Apache::Qpsmtp is currently included in the trunk. A setup exemple is included with the runtime. The qpsmtpd-forkserver method is used by perl.org and cpan.org. For me, that's more than enough!


(shamelessly copied from Open Source Tips):

The qpsmtpd daemon is easy to install and requires only a few simple pre-requisites. You
need to install the following CPAN modules (use the cpan command to install these). 
  * Net::DNS 
  * MIME::Base64 
  * Mail::Header 

If you use a version of Perl older than 5.8.0, you will also need the following modules. 
  * Data::Dumper 
  * File::Temp 
  * Time::HiRes 

Moving on to the qpsmtpd installation, first, you need to download the qpsmtpd
source code. I think using the source code gives a better picture of how qpsmtpd
is put together but you can also install via RPM if you prefer. You can find
instructions about how to install via RPM at the qpsmtpd Wiki. 

The current release of qpsmtpd is version 0.32 and you can download it with this command:
wget http://smtpd.develooper.com/files/qpsmtpd-0.32.tar.gz

(A slightly more recent version is available in the stable branch of the qpsmtpd
subversion repository; it addresses some issues that have arisen since the last
release. Download it via the svn tool:
svn co http://svn.perl.org/qpsmtpd/branches/0.3x qpsmtpd-0.3x)

Unpack the source code, change into the resulting directory, create the Makefile and make the package, like so: 
  # tar -zxf qpsmtpd-0.32.tar.gz
  # cd qpsmtpd-0.32
  # cd qpsmtpd-0.32
  # perl Makefile.PL
  # perl Makefile.PL
  # make
  # make

Once the package is compiled, I strongly suggest you test it by doing:
  # make test

My first time through, I didn't and missed some things during install.

Once the package is compiled, you can install it using the make install command. 
  # make install

This will install the Qpsmtpd.pm Perl module and its associated modules into the
location of your Perl site files, for example, on a Linux-based host at
/usr/lib/perl5/site_perl/5.8.8. The qpsmtpd and qpsmtpd-forkserver binaries will
be installed into the /usr/bin directory. 

Next, create a user to run qpsmtpd, I've chosen the user smtpd, like so: 
  # useradd smtpd -s /sbin/nologin

I have used the -s option to set the user's shell to /sbin/nologin, which prevents
the smtpd user from logging in. 

Now we want to create and configure some directories and basic configuration files.
As a result of its heritage as a replacement for the qmail-smtpd daemon, the
qpsmtpd daemon requires directories to be in a particular structure. The easiest
way to implement this is to locate these directories off the home directory of the
user qpsmtpd is running as. This allows qpsmtpd to find the required configuration
files, logging directory and the plug-ins. 

As a result of this non-FHS behavior, we're also going to create some symbolic
links to make qpsmtpd look a bit more FHS compliant. 

Create a configuration directory and populate it with the sample configuration
files that are supplied with the qpsmtpd package. 

  # mkdir /etc/qpsmtpd
  # cp qpsmtpd-0.32/config.sample/* /etc/qpsmtpd
  # chown -R smtpd:smtpd /etc/qpsmtpd

Then link that directory to the smtpd user's home directory like so: 
# ln -s /etc/qpsmtpd ~smtpd/config

Next, create a logging directory and link it in the same way. 
  # mkdir /var/log/qpsmtpd
  # chown smtpd:smtpd /var/log/qpsmtpd
  # chmod 0750 /var/log/qpsmtpd
  # ln -s /var/log/qpsmtpd ~smtpd/log

Then we need to create a temporary directory for qpsmtpd. 
  # mkdir ~smtpd/tmp
  # chown smtpd ~smtpd/tmp
  # chmod 0700 ~smtpd/tmp

Finally, we need to install the qpsmptd plug-ins by moving them out of the package
directory. I usually choose to install the plug-ins into the /usr/share/qpsmtpd
directory and link it back to the smtpd user's home directory. 

  # mkdir /usr/share/qpsmtpd
  # mv qpsmtpd-0.32/plugins /usr/share/qpsmtpd
  # ln -s /usr/share/qpsmtpd/plugins ~smtpd/plugins

Now you have installed qpsmtpd you can start it. The qpsmtpd daemon can be run
in a number of different modes including tcpserver (using daemontools), a forkserver
daemon (which forks for each new connection) and Apache::Qpsmtpd (where qpsmtpd
is run via Apache 2 and mod_perl 2). There is also a pollserver daemon using Danga
that is currently being developed and is not yet suitable for production use. 

I'm going to examine running qpsmtpd via the forkserver daemon, which is considered
the most popular mode and how perl.org and cpan.org both run their instances of qpsmtpd. 

Earlier we installed the qpsmtpd-forkserver binary in the /usr/bin/ directory. Now
we're going to symlink this binary into the ~smtpd directory to keep our configuration

# ln -s /usr/bin/qpsmtpd-forkserver ~smtpd

Once we've done this, we can start the qpsmtpd forkserver, 

# ~smtpd/qpsmtpd-forkserver

This launches the forkserver in the foreground. Without any options the forkserver
will bind to all available local IP addresses on port 2525 and wait to receive email.
We can override these options on the command line like so, 

~smtpd/qpsmtpd-forkserver -l -p 25 -u smtpd -d --pid-file /var/run/qpsmtpd-forkserver

The forkserver initiation on the previous line uses the –l option to specify the IP
addresses to bind, here The –p option specifies the port to bind to,
in this case port 25. In the 0.32 release, you can only specify one IP address and
port to bind to. In the 0.3x unstable release, you can specify the -l and -p options
multiple times to bind to multiple IP addresses and ports. 

The -u option indicates what user to run qpsmtpd as and the -d option tells the
forkserver to detach and run as a daemon. If you omit the –d option, then qpsmtpd
will run in the foreground. Lastly, the --pid-file option specifies the location
of the daemon's PID file. 

You can start qpsmtpd-forkserver from the command line as I've demonstrated or
via a SysV-style init script. You can see an example of an init script at
http://wiki.qpsmtpd.org/deploy:sysvinit .

You can test that qpsmtpd is working by telnet'ing to the qpsmtpd server like so: 

# telnet 25
Connected to mail.domain.com (
Escape character is '^]'.
220 domain.com ESMTP qpsmtpd 0.32 ready; send us your mail, but not your spam. 

Type QUIT to exit the telnet session.


Citadel Changes

First, from WebCit, go to: "Edit site-wide configuration" -- "Network" and set "SMTP MTA port (-1 to disable)" to 2525. Restart the server for this to take effect.

qpsmtpd Configuration

First, create the file **/etc/qpsmtpd/rcpthosts** and enter your domains that you support. I set my system up to log to a file:
  * First, create /var/log/qpsmtpd directory
  * Change the permissions to smtpd:smtpd so qpsmtpd can write to the file
  * Create the file **/etc/qpsmtpd/logging** and enter:
  logging/file loglevel LOGINFO /var/log/qpsmtpd/qpsmtpd.log
In the config file **/etc/qpsmtpd/plugins**, the key entry that **must** be configured is:
queue/smtp-forward localhost 2525
This tells qpsmtpd to forward all received email to port **2525** (our Citadel port).

Here's my current **/etc/qpsmtpd/plugins** config file

#  Example configuration file for plugins

# enable this to get configuration via http; see perldoc
# plugins/http_config for details.
#   http_config http://localhost/~smtpd/config/  http://www.example.com/smtp.pl?config=

# The hosts_allow module must be loaded if you want the -m / --max-from-ip /
# my $MAXCONNIP = 5; # max simultaneous connections from one IP
# settings... without this it will NOT refuse more than $MAXCONNIP connections
# from one IP!


count_unrecognized_commands 4



# sender_permitted_from

# this plugin needs to run after all other "rcpt" plugins

# content filters

# You can run the spamassassin plugin with options.  See perldoc
# plugins/spamassassin for details.

# rejects mails with a SA score higher than 20 and munges the subject
# of the score is higher than 10.
spamassassin reject_threshold 10 munge_subject_threshold 5

# run the clamav virus checking plugin
# virus/clamav

# run the clamdscan virus checking plugin
virus/clamdscan deny_viruses yes clamd_socket /var/run/clamav/clamd.sock

# queue the mail with qmail-queue
queue/smtp-forward localhost 2525

# If you need to run the same plugin multiple times, you can do
# something like the following
#    check_relay
#    check_relay:0 somearg
#    check_relay:1 someotherarg

Feel free to contact me on our #citadel IRC channel (I'm drmikecrowe).

There are no social media links here. Enjoy a friendly Citadel community instead. Or go outside.