intelligent greylisting daemon for postfix
Python Makefile Other
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


bley is an intelligent greylisting daemon for Postfix (and Exim).

It uses various test (incl. RBL and SPF) to decide whether a sender should be greylisted or not, thus mostly eliminating the usual greylisting delay while still filtering most of the spam.



bley is written in Python using the Twisted framework. It uses pyspf for SPF validation and publicsuffix for checking of domains against the database. Database interaction is implemented via sqlite3 for SQLite, psycopg2 for PostgreSQL and MySQL-Python for MySQL.


Quick and dirty

Unpack the tarball (or clone the git tree), adjust bley.conf.example, rename it to bley.conf and run ./bley.

Still quick, but not dirty

Unpack the tarball (or clone the git tree), run python build followed by python install, copy /etc/bley/bley.conf.example to /etc/bley/bley.conf, adjust it to your needs (see CONFIGURATION below) and run /usr/bin/bley.


Basically you just have to configure the database:

dbtype = pgsql for PostgreSQL, mysql for MySQL or sqlite3 for SQLite
dbhost = the host where the database runs on (usually localhost)
dbport = the port where the database runs on (can be left unset for
         the default 5432 for PostgreSQL and 3306 for MySQL)
dbuser = the name of the database user
dbpass = the password of the database user
dbname = the name (or path in case of SQLite) of the database
dbpath = you can also set the path separately and load ${dbpath}/${dbname}

After that you can point your Postfix to bley as a policy server by adding check_policy_service inet: to your smtpd_recipient_restrictions in

bley will be working now, but you probably would like to tune it more for your needs (esp. the used DNWLs and DNSBLs, the greylisting times and the hit thresholds).

Additional Configuration

Sometimes, you want to bind bley to something else than, this can be achieved with the following two parameters.

listen_addr =
listen_port = 1337

As bley is designed to be a deamon, it will write a pid file and a log file. The locations of the two can be configured with the following parameters.

pid_file =
log_file = bley.log

Setting log_file to the special word syslog will make bley log to syslog instead of a file, using the mail facility.

If you want to inform the sender about the greylisting, you can adjust the message sent via

reject_msg = greylisted, try again later

The DNSWLs and DNSBLs bley uses for its tests can be set via

dnsbls =,,
dnswls =

Thresholds define how many sub-checks have to hit, to trigger a feature (whitelisting in case of dnswl, greylisting in case of dnsbl and rfc).

dnswl_threshold = 1
dnsbl_threshold = 1
rfc_threshold = 2

How long should a sender be greylisted, when should we allow him in at the very last and how long should he have to wait more, if he retries to early (all in minutes)?

greylist_period = 29
greylist_max    = 720
greylist_penalty= 10

After how many days should old entries be deleted from the database? Entries of senders who have not verified to be "good" should be purged earlier.

purge_days = 40
purge_bad_days = 10

SPF (Sender Policy Framework) checks can be turned off. SPF Best Guess should always be turned off.

use_spf = 1
use_spf_guess = 0

If you use Exim instead of Postfix, set this to 1. It will automatically close connections after the decision is sent. While Postfix supports checking multiple senders over the same connections, Exim does not. In fact it even closes the sending part of the socket as soon all details have been transmitted.

exim_workaround = 0


In some situations, it is useful to be able to whitelist senders or recipients. This can be done by providing lists as files (syntax is postgrey compatible).

whitelist_recipients_file = ./whitelist_recipients
whitelist_clients_file = ./whitelist_clients


This file contains a list of recipients who are excluded from greylisting. One entry per line. An entry can be either a full email address, the local part, a domain name or a regular expression:


This file contains a list of clients who are excluded from greylisting. One entry per line. An entry can be either an IP adress, a subnet, a domain name or a regular expression.


Known sender

The first check is, of course, whether our database already knows about the (ip, sender, recipient) tuple. If it does, act accordignly, otherways continue with the other checks.


Check whether the sender IP address is listed in the configured DNSWLs and DNSBLs. If either one reaches the configured threshold, the mail is considered good or bad, depending on which threshold was reached.


While the following checks are not all about stricktly implementing the RFC, all of them try to identify suboptimal behaviour of the sending MTA, which often indicates a spammer.


Check whether the name used in HELO/EHLO matches the reverse DNS entry.


Check whether the hostname looks like a dynamic one.

sender equals recipient

People usually do not send mail themself "over the Internet" (and local mail should not be checked by a policy daemon). Spammers on the other hand, often try to bypass address-checks by using the same address as sender and receiver.


The Sender Policy Framework allows domain owners to define which servers are allowed to send mail using their domain and which are not.


bley includes a small graphing utility called bleygraph. It will analyze the bley_log table of the database, and plot a few graphs using matplotlib.

There is not much configuration possible for bleygraph: the database settings are taken from the bley section of bley.conf and the path for the graph output (destdir) is the only setting in the bleygraph section of the configuration file.



For exim4, we can install the following ACL:

# Check policy service "bley", using the postfix policy service protocol.
 defer log_message = greylisted host $sender_host_address
        set acl_m0 = request=smtpd_access_policy\n\
        set acl_m0 = ${sg\
           message = ${sg{$acl_m0}{^\\w+\\s*}{}}
         condition = ${if eq{${uc:${substr{0}{5}{$acl_m0}}}}{DEFER}{true}{false}}

# Warn if delayed
warn message = ${sg{$acl_m0}{^\\w+\\s*}{}}
   condition = ${if eq{${uc:${substr{0}{7}{$acl_m0}}}}{PREPEND}{true}{false}}

On a Debian system using split configuration for Exim, this can be placed in a file, for instance /etc/exim4/greylist.bley.conf, and included from the RCPT acl by setting the CHECK_RCPT_LOCAL_ACL_FILE variable to point to that file, in /etc/exim4/conf.d/main/01_local-variables.

# /etc/exim4/conf.d/main/01_local-variables
CHECK_RCPT_LOCAL_ACL_FILE = /etc/exim4/greylist.bley.conf


Build Status