#!/usr/local/bin/perl # This will filter incoming email, bouncing the rejects back to sender. This # program is copyright 2003 by Anthony Boyd. It it released under the BSD # license, which means you can modify & run this for personal use, commercial # use, or even military use. However, it also means I assume NO liability, # and this copyright must remain in place. I encourage you to freely modify # and bugfix this code, as I probably won't. This is a beta release, version # 0.5 released on May 31st, 2003. It needs fixes to work better with Exim. # With this file, you should have received 2 others -- a readme file that # gives you a step-by-step guide to setting this up, and the BSD license. If # you didn't get these, somebody isn't playing nice. Visit # http://www.outshine.com/filter/ for the missing files. # Initialize the needed modules. use warnings; use strict; use Mail::Audit; use DBI; # HERE BEGINS THE SECTION THAT YOU NEED TO CONFIGURE. # Number of hours before replying to the same person. Prevents mail loops. my $safetypause = 24; # A path (of your choosing) to a file where this program can log messages. my $errorlog = '/home/youraccount/errorlog.txt'; # The path to your maildir directory or your mbox file. my $mailbox = '/home/youraccount/mail/mailbox/'; # The path to a backup maildir directory or mbox file. When all else fails. my $backupmailbox = '/home/youraccount/mail/backupmailbox/'; # The DBI driver for your database. If you're unsure, PHPMyAdmin shows it. my $driver = 'DBI:mysql:yourdatabasename:localhost'; # Database login name and password. my $username = 'foo'; my $password = 'bar'; # The account itself -- the email address that you're using. my $email = 'email@address.com'; # HERE ENDS THE SECTION THAT YOU NEED TO CONFIGURE. # The rest of the variables we'll setup automatically, no need to manually # change anything else. It should "just work" from here, but if you'd like, # you can change the bounce message below. Keep your text between the # ENDMESSAGE markers. Don't remove those. my $message = <<"ENDMESSAGE"; The address $email only accepts email from a small list of approved domains. Sorry. You will only receive this reply once every $safetypause hours, even if you send many messages at once. ENDMESSAGE # Get the logfile and database ready for action. my (@whitelist, @spamlist, $database, $query, $result, $sql, $mail, $sender, $address); open (LOGFILE, ">>$errorlog") or die "Unable to open log file!\n"; $database = DBI->connect($driver, $username, $password) or die "Can't connect to database!\n"; # Get the email and find out who it's from. $mail = Mail::Audit->new(emergency=>"$backupmailbox"); $sender = $mail->from; print LOGFILE "Incoming mail from $sender.\n"; # Let's setup the @whitelist array. $sql = "SELECT DISTINCT(friendsemail) FROM friends WHERE myemail='$email'"; $query = $database->prepare($sql); $query->execute; while ($result = $query->fetchrow_array) { push(@whitelist, $result); } $query->finish; # Quick check to abort if there is no whitelist. unless (scalar @whitelist) { print LOGFILE "No whitelist! We're accepting the mail and bailing out.\n"; cleanup(); $mail->accept($mailbox); } # Let's setup the @spamlist array. $sql = "SELECT DISTINCT(email) FROM spammers WHERE reason='spam'"; $sql .= " AND time > (NOW() - INTERVAL " . $safetypause . " HOUR)"; $query = $database->prepare($sql); $query->execute; while ($result = $query->fetchrow_array) { push(@spamlist, $result); } $query->finish; # Time to go through the whitelist and accept the email if it matches a # known-good address. foreach $address (@whitelist) { if ($sender =~ /$address/i) { print LOGFILE "Accepting mail from $sender.\n"; cleanup(); $mail->accept($mailbox); } } # Well, the mail isn't from a known-good address if this is still running at # this point, so let's ignore the email if we know about this spammer, or else # bounce the email if it came from a new/unknown source. if (grep /$sender/, @spamlist) { print LOGFILE "Serial spammer $sender ignored, for now.\n"; cleanup(); $mail->ignore; } else { $sql = "INSERT INTO spammers (reason, time, email) VALUES"; $sql .= " ('spam', NULL, '" . $sender . "')"; $query = $database->prepare($sql); if($query->execute) { print LOGFILE "Added $sender to spam list.\n"; } else { print LOGFILE "WARNING! Failed to add $sender to spam list.\n"; } $query->finish; # This will remove outdated spammer entries. $sql = "DELETE FROM spammers WHERE time < (NOW() - INTERVAL"; $sql .= " " . ($safetypause * 2) . " HOUR)"; $query = $database->prepare($sql); $query->execute; $query->finish; cleanup(); $mail->reject($message); } # This just closes the database and logfile. sub cleanup { unless ($database->disconnect) { print LOGFILE "Unable to close the database connection.\n"; } print LOGFILE "\n"; close(LOGFILE); } cleanup();