Friday, October 24, 2008

Stop undeliverable spoofed spam using maildrop and PHP

A common problem among email providers is the growing practice of spammers using legitimate email addresses in the From: header of their messages, which means that unsuspecting users get flooded with potentially thousands of undeliverable messages due to the fact that many of the To: addresses on the spammers' lists are no longer valid.
A few of our customers had this issue, so I devised a quick way to filter out the undeliverable messages via Maildrop and php.

1. Set Postfix to pass mail through Maildrop

After installing maildrop (it should be readily available in your *nix distro's packaging system) Make sure Postfix is set up to pass mail to Maildrop by putting the following line in your file:

maildrop unix - n n - - pipe
flags=DRhu user=vmail argv=/usr/local/bin/maildrop -d ${recipient} ${recipient}

(Note: adjust maildrop according to your environment - see

2. Place the following code in /usr/local/etc/mail/maildrop_filters.php

ini_set('display_errors', 'off');


$recipients = array(

$bad_subjects = array(
'Undelivered Mail',
'Delivery Status Notification',
'Undeliverable mail',
'Returned Mail',
'Delayed Mail',
'Delivery Failure',
'Warning: could not send message',
'Warning: message'

// Don't edit below here
$sender_address = $argv[1];
$recipient_address = $argv[2];

$stdin = fopen('php://stdin', 'r');
$msg = '';
$header = '';

while ( $buf = fread($stdin, 500) ) {
$msg .= $buf;

$msg_lines = explode("\n", $msg);

if ( is_array($msg_lines) ) {
foreach( $msg_lines as $cur_line ) {

$cur_line = trim($cur_line);

if ( $cur_line == '' ) {

$header .= $cur_line . "\n";


foreach( $recipients as $recipient ) {

if ( preg_match('/^To\:\s*\

foreach( $bad_subjects as $subj ) {

if ( preg_match("/^Subject:\s*" . preg_quote($subj) . "/im", $header) ) {

echo $msg;


3. Add the following to your maildroprc file, which will probably be in /etc, /etc/mail, or /usr/local/etc/:


exception {
xfilter "/usr/local/bin/php /usr/local/etc/mail/maildrop_filters.php \"${SENDER}\" \"${RECIPIENT_ADDRESS}\""

if ( $RETURNCODE == 1 )
log "${OUTER_INDENT} Message for ${RECIPIENT_ADDRESS} discarded. Returncode was ${RETURNCODE}"

4. Edit the $recipients array

Go back into /usr/local/etc/mail/maildrop_filters.php and edit the $recipients array as necessary - this is where you put the addresses that are being bombarded with the undeliverable mail messages:

$recipients = array(

Additionally, you can add or remove subjects from the $bad_subjects array as required. Note that the filter matches subjects that *start* with the items listed in $bad_subjects, so "Undeliverable:" will match "Undeliverable: Mailbox not found" and "Undeliverable: Mailbox is full", and so on.

Wednesday, October 22, 2008

SwiftFile - Send files securely on the web

As the latest in a series of webtools that Context is launching, we've decided to offer an extremely easy, free, secure solution for uploading and sending files. offers a simple interface to upload and password protect files, making them unreadable even to the site administrator. Our goal was not to compete with filesharing giants like sendspace, mediafire, or rapidshare, but rather to offer a way to send sensitive documents very quickly and very securely. You can read the SwiftFile FAQ for information about how the data is stored and encrypted. Give it a try - it's fast, easy, and free. Additionally, thanks to the Fuse PHP framework, the site was put together from start to finish in 2 modest work days. We're hoping that a side effect of these tools will be to showcase the versatility and ease of use of the framework, which is now gaining ground in the PHP MVC community.

Sunday, October 19, 2008

suphp directory not owned by user

Installing suPHP on Apache 2 tonight, I was surprised that it was complaining about the parent directory for my document root not being owned by the specific user who owned the scripts. I had it owned by the apache user, www, and it turns out it (the parent directory which, for me, was /home/www) has to be owned by root in order for suPHP to traverse it.