Home | Comics | Gallery | wishlist | Donations | Impressum | The Book of Postfix | Postfix - Einrichtung, Betrieb und Wartung | Blog | |

Mailserver for mobile users with Postfix

You know the problem: You're having a mailserver and you offer SMTP and POP/IMAP for your customers, but you don't want to be abused as an open relay!

Problem: How can one distinguish spammers from legitimate users?

Possible approaches:

Checking the envelope-from (MAIL FROM: <sender>):

Not recommended, since the spammer can specify a random sender address, even one of a legitimate user. And that's just what they do :)
So it's utterly useless -- in fact this restriction is used only by administrators who have no grasp of how SMTP actually works.

POP/IMAP-before-SMTP authorization:

The user must authenticate himself from the same IP address he'll later use to send his email from. This is only possible during a small time-frame after the POP or IMAP authentication.


The most elegant method. During the SMTP Dialogue, the sending machine specifies username and password. If this authentication is successful, relaying will be permitted.


The IP addresses of clients with successful authentication are stored in a database. The key is the IP address, the value is the timestamp of when the authentication occured. The daemon that manages the database checks the database periodically for entries to purge, once the time-frame expired.

Realisation of POP-before-SMTP with Postfix

For Postfix there are at least three daemons:

All three have their pros and cons:

dracd pros:

dracd cons:

pop-before-smtp in C pros:

pop-before-smtp in C cons:

pop-before-SMTP.pl pros:

pop-before-SMTP.pl cons:

For these reasons, my choice is pop-before-SMTP.pl.

Configuration of pop-before-SMTP.pl:

First, download the program from here.

Start the daemon at boottime. Right now, we'll start the daemon manually.

By default pop-before-SMTP.pl looks at /var/log/maillog, extracts the IP of clients which performed a successful login and writes these to a hash map /etc/postfix/pop-before-smtp.db.

The parameters are as follows:

nohup pop-before-smtp \
      [--[no]write] \
      [--[no]debug] \ 
      [--[no]flock] \
      [--grace=seconds] &


enables debugging, but usually only the regular expression that extracts the IP is wrong.


specifies the time window during which relaying will be allowed. Default 1800 seconds.


specifies the logfile. Per default, this is /var/log/maillog, but comman names are /var/log/mail or /var/log/messages.


prevents writing of the database file.

Should you encounter errors when starting pop-before-SMTP.pl you might be missing essential Perl Modules; you can install them using:

% perl -MCPAN -e shell;
% install Time::HiRes
% install File::Tail
% install Net::Netmask
% install Date::Parse
% install DB_File

pop-before-smtp.pl is configured to parse the logfile entries produced by UW-ipop3/imapd. To make it work with other daemons, you must change $pat and $pat2. You can find them following this text:

# This regex pull the lines I'm interested in out of $logfile, and yanks out
# the timestamp and IP address

For SuSE 8.2:

# Testpattern qpopper for SuSE 8.2 Personal after Update
$pat = '^(... .. ..:..:..).* (\d+\.\d+\.\d+\.\d+) \[pop_updt\.c:296\]$';

Test in Postfix:

You can query the contents of the hash database /etc/postfix/pop-before-smtp.db using postmap:

% postmap -q xxx.xxx.xxx.xxx hash:/etc/postfix/pop-before-smtp

should return an OK for xxx.xxx.xxx.xxx (if and only if a successful POP/IMAP Login was performed from that IP).

Integration into Postfix:

The default-restrictions:

smtpd_recipient_restrictions = 

must be extended to:

smtpd_recipient_restrictions = 
   check_client_access hash:/etc/postfix/pop-before-smtp,

That means: Whenever a client doesn't belong to $mynetworks, Postfix queries hash:/etc/postfix/pop-before-smtp, where pop-before-smtp.pl puts the IP addresses of authorized clients.
If the client's address is found there, Postfix interprets the all-numeric value for the entry (the RHS) as OK and the mail is accepted for delivery.

© by Ralf Hildebrandt
This document contains links to external information sources that I do neither monitor nor control. I explicitly disclaim any liabilities in respect to external references.
You are getting this document without any guarantees. Any methods shown above are meant as demonstration and may be wrong in some place. You may damage your system if you try to follow my hints and instructions. You do this at your own risk!

Valid HTML 4.01 Strict

This file was last modified 27. Apr 2007 by root