If you have an email address for a while, you’ll know that “spams” are almost inevitable. Once the email address has been used, spams will find their way there sooner or later. Combating email spams has also become one of the most researched topics these days.
Greylisting is a relatively new method to use against spams, and its principle is very different from traditional content filtering/content classifying strategy. The differences make it very effective in stopping spams currently, utilising relatively little CPU time and has small memory footage. It by no means is a replacement for fiter/classifier based spam protections, but can be easily deployed as first level of defense to reduce the CPU/memory demand of your spam filters.
This article was written after successfully implementing greylisting on Postfix using Gld, on a memory-restrained VPS running Gentoo Linux. Hopefully it will be useful to those who are thinking of implementing a similar solution.
What is Greylisting?
What makes greylisting different from other filter/classifier based defense, like SpamAssassin and SpamBayes? From Greylisting website:
In name, as well as operation, greylisting is related to whitelisting and blacklisting. What happen is that each time a given mailbox receives an email from an unknown contact (ip), that mail is rejected with a “try again later”-message (This happens at the SMTP layer and is transparent to the end user). This, in the short run, means that all mail gets delayed at least until the sender tries again – but this is where spam loses out! Most spam is not sent out using RFC compliant MTAs; the spamming software will not try again later.
As most spams are sent out by bots/dumb SMTP clients, they do not bother to try again after the SMTP server replies with temporary failure, where a properly implemented SMTP MTA would continue to re-try for a certain amount of time. It effectively blocks out majority of spams without actually scanning through their contents.
For example, the following chart shows the number of spams caught by SpamAssassin on daily basis, on my mail server serving 3 real users. At the beginning of August I set up greylisting, and the number of spams per day dropped dramatically. That means I only need to run one SpamAssassin instance (which is huge at around 30Mb RSS per process), and it does not need to work that hard analysing incoming emails.

Pretty obvious, isn’t it? Now, let’s get into how to set it up.
Requirement
You need the following packages installed.
- Postfix 2.1 or greater.
- MySQL or PostgreSQL.
- Gld or GreyList Daemon.
Since I was setting it up on Gentoo Linux, I will use emerge to install these packages. In my case, MySQL is used to store the greylisting database.
# emerge -auv postfix mysql gld
It shall download, compile and install these packages if they haven’t yet been installed. Your mileage might vary, if you are using a different distribution.
Setting up Gld
First of all, you need to create a MySQL database for Gld. Start MySQL if it hasn’t been started, and let’s create a new database called gld.
$ mysql -uroot -p
mysql> CREATE DATABASE gld;
mysql> GRANT ALL PRIVILEGES ON `gld`.* to gld@localhost
IDENTIFIED BY '<gld password>';
mysql> ALTER DATABASE `gld` DEFAULT CHARACTER SET latin1;
mysql> USE gld
mysql> \. /usr/share/gld/sql/tables.mysql
Note — on Gentoo with MySQL 4.1 onwards, the default character set is UTF8, which caused the greylisting table unable to be created as index key will be too large. Therefore it is necessary to set the database charset to “latin1″ before populating the tables.
Now, open the Gld configuration file /etc/gld.conf and start working through it. The default setting is pretty sane, and you only need to change the database configuration at the very end of the file.
# ## SQL INFOS (defaults are localhost,myuser,mypasswd,mydb) # #SQLHOST=localhost SQLUSER=gld SQLPASSWD=<gld password> SQLDB=gld
You can then start the gld and add it to a list of start up items.
# /etc/init.d/gld start # rc-update add gld default
Gld comes with a list of whitelist that you should consider using. If email is originated from one of the whitelisted addresses, it will be let through without greylisting. To populate the default whitelist:
# mysql -u root -p gld < /usr/share/sql/gld/table-whitelist.sql
Setting up Postfix
Setting up Postfix mail server is really outside the scope of this article, and should be left as exercise for the readers. I have following lines in my /etc/postfix/main.cf to enable SASL authentication, manual whitelist/blacklist and greylisting.
smtpd_recipient_restrictions =
reject_unauth_pipelining,
reject_non_fqdn_recipient,
reject_unknown_recipient_domain,
permit_mynetworks,
permit_sasl_authenticated,
check_recipient_access hash:/etc/postfix/recv_access,
check_client_access hash:/etc/postfix/client_access,
reject_unauth_destination,
check_policy_service inet:127.0.0.1:2525,
permit
Configuration files /etc/postfix/recv_access and /etc/postfix/client_access allow manual blacklist/whitelist before automated greylisting. For example if I wish to have my secondary MX (free service at The Roller Network) to be always whitelisted, I can have the following entries in my client_access file.
# mail.rollernet.us mail2.rollernet.us 208.11.75.2 PERMIT 216.90.171.2 PERMIT
Run postmap /etc/postfix/client_access to create the hash file. The same applies to recepient whitelist/blacklist in /etc/postfix/recv_access. For example to allow some critical addresses to always pass through without greylisting:
postmaster@ PERMIT hostmaster@ PERMIT abuse@ PERMIT
Note that I do not use any Realtime Black Lists (RBL) in my receipient restriction, as personally I found them often produce false positives. Recently Gmail SMTP servers were blocked by SpamCop and ORDB, and I have no idea how many legitimate emails I have rejected until someone contacted me via a web form on this site. It does allow open-relay mail servers to leak spams through our greylist, but I guess I am willing to accept that than loosing valuable mails.
Now, reload Postfix to activate the changes.
# /etc/init.d/postfix reload
Now, enjoy reduced spams and virii!
Tuning Greylisting
Gld came with quite a few configuration options which can be found in /etc/gld.conf. Default configuration works very well.
However, in the original greylisting whitepaper, there are three values to consider when dealing with (from, to, ip) triplets:
- Initial delay of a previously unknown triplet: 1 Hour
- Lifetime of triplets that have not yet allowed a mail to pass: 4 Hours
- Lifetime of auto-whitelisted triplets that have allowed mail to pass: 36 Days
Gld only allows you to change (1), that is MINTIME in the configuration file which defaults to 60 seconds — far smaller than the one hour suggested. I actually doubt that people are willing to wait for one hour for the very first email from a new correspondant to be white-listed, and the whitepaper also suggested that
The data collected during testing showed that more than 99% of the mail that was blocked with the tested setting of 1 hour would still have been blocked with a delay setting of only 1 minute.
Increase that to 5 minutes or 10 minutes or even one hour if you want, but I am leaving mine to 60 seconds.
What Gld did not provide is the option to expire greylist (2) and whitelist (3). Expiring greylist is needed to prevent spammer spamming the same address in the future, which might in turn whitelist the record. 4 hours is a bit short I found, as some properly implemented mail servers don’t re-try that often. Expiring whitelist is also needed to keep the size of database sane, as it purges those once-off records.
Fortunately Gld kept all its records in the database, and it is easy to write a script that expires those records. Here’s mine:
#!/bin/bash # Expiring the greylist in 12 hours. EXPIRE_GREYLIST=43200 # Expiring the whitelist in 35 days. EXPIRE_WHITELIST=$((35 * 86400)) echo " DELETE FROM greylist WHERE last<$((`date +%s` - EXPIRE_WHITELIST)); DELETE FROM greylist WHERE n=1 AND first<$((`date +%s` - EXPIRE_GREYLIST)); " | mysql gld
Run this in a cron job (say once every hour) to keep the Gld greylist database clean.
Why am I still getting spams?
Greylisting does not eliminate all spams, once for all. Especially when the spammers have smarten up, it is likely they will find ways to work around it. In my case I am still getting a few spams everyday, and they usually get quarantined by SpamAssassin so none of them ended up in my inbox. Analysing those that are filtered by SpamAssassin, I can conclude that:
- Greylisting without RBL cannot block spams from open-relay mail servers. Those servers are not bots and they do retry if they failed to forward the spams to my inbox. Thus greylisting has no use here.
- Greylisting does not work with redirected emails. I have several email addresses on other services that redirect to my main inbox, and these servers have not implemented greylisting.
- It is easier to spam secondary MX if it does not implement greylisting.
- Some spammers do send from legitimate email servers.
Having a content filtering helps to remove its short-comings. I use SpamAssassin + Amavisd + ClamAV, which help to almost eliminate the spams I have received everyday.
Hopefully this article is useful. Comments, corrections and suggestions are welcome.

14
Akismet worked for me and the spammers. Die pls spammer thx.
Eric — we are talking about email spams here, NOT comment spams.
It would be interesting whether Akismet can work for comment spam, but I can imagine that it would result a much heavier load on its server.
What Gld did not provide is the option to expire greylist (2) and whitelist (3)
What about
gld -c nandgld -k n? Or is that not the same? I must admit I’m still a bit confused as to why it is useful to expire the greylist/whitelist. The more I read your explanation, the less I understand it ;-)BTW: thank you for this blog entry – that’s exactly what I was looking for!
Thanks! I must have missed that option (and tried to roll my own)!
GLD uses MyISAM tables by default, which under any kind of load will cause your service to hang and load on your mail servers to jump up. This happens because MyISAM locks the entire table during an insert. You should change the storage type in /usr/share/gld/sql/tables.mysql to InnoDB. InnoDB uses row level locking and will not cause your selects to block while inserts are happening. InnoDB can be memory intensive, so take the time to tune MySQL.
Hmmm, my gld version does also support the c/C and k/K option he mentioning. Maybe you had an outdated version? I have 1.7 here.
Anyway. I have rewritten you shell script to PHP. Maybe some people doesn’t have shell access. I have also rewritten the WHERE statements to let the database provide the unix timestamp and not the script.
Here are the links:
http://www.mxchange.org/downloads/greylist-expire.phps
http://www.mxchange.org/downloads/greylist-expire.zip
Why not use the “memory” MySQL table scheme, where rows are stored in memory altogether? This will cause data to be lost if the mysql server is restarted, but isn’t that OK for greylisting?
Nice idea, even when my reply takes so long. ;-) That would result in fastest graylist-handling. And turning MyISAM/InnoDB to memory isn’t that hard. Sorry for maybe broken english. ;)
Hello
I need to know more information about this three hosting companies
Host1Plus
GoDaddy
1&1 Hosting
I need just your opinions (not your friends or info from other forums)
Hello,
I have 3 domains/sites hosted on my hosting plan on Bluehost.
Sites are small (~100 visitors/day), no forums ect…
After a two weeks there will be expiration date and I’m thinking about migrating to other hosting company.
Bluehost is OK until you saw his uptime and it is terrible for me about speed!
They’re veeeery slow!
(I’m from Germany, EU)
So, recently I found a Host1Plus.com
Any experience with this hoster, anyone?
It looks like much faster and have more servers in variuos world countries.
And at this moment they offer 15% discount with coupon code – FORUMS
Should I go there?
Any opinions will be appreciated. Please share your thoughts.
Thank You and sorry for my english…
@Crzynewbaby Try https://members.nearlyfreespeech.net/ host. VERY cheap for normal sites and professional too.
@Sune et al:
The memory tables suggestion is quite old but still I’m writing this to suggest others not doing memory tables. Why? In my company we are using a simple gld daemon and we handle lots of emails, hence the database is growing up like crazy even with the standard expiration dates. This means my table is right now around 1.5G big, which if stored in memory would make my machine just die. I would suggest using InnoDB instead.
Also, even though I can’t recall now how, you can also make postfix soft-failing if the gld daemon is not running or can’t perform the check within a reasonable period of time, thus avoiding your email service to get down because of an external process to postfix itself. It will of course allow some spam leaks, but like scotty said, it is always better to have little spam rather than loosing ham emails.
About InnoDB,
GLD supports it natively?
I can change MyISAM to InnoDB tables and to expect GLD works again without any other changes in software?
Thanks a lot
Regards
Why not? GLD just does SQL queries, it doesn’t care the engine underneath. The problem with memory tables is not because of any “non supported” feature, but instead because the table growth in memory could reach the mysql limits, or even worse: the system limit.
I use GLD with InnoDB tables and it works like a charm.