#!/usr/bin/ruby # Handle email responses sent to us. # # This script is invoked as a pipe command, i.e. with the raw email message on stdin. # - If a message is identified as a permanent bounce, the user is marked as having a # bounced address, and will not be sent any more messages. # - If a message is identified as an out-of-office autoreply, it is discarded. # - Any other messages are forwarded to config.get("FORWARD_NONBOUNCE_RESPONSES_TO") # We want to avoid loading rails unless we need it, so we start by just loading the # config file ourselves. $alaveteli_dir = File.join(File.dirname(__FILE__), '..') $:.push(File.join($alaveteli_dir, "commonlib", "rblib")) load "config.rb" MySociety::Config.set_file(File.join($alaveteli_dir, 'config', 'general'), true) MySociety::Config.load_default def main Dir.chdir($alaveteli_dir) do load_rails raw_message = $stdin.read pfa = permanently_failed_address(raw_message) if pfa.nil? not_a_bounce(raw_message) else record_bounce(pfa, raw_message) end end end def permanently_failed_address(raw_message) message = TMail::Mail.parse(raw_message) if message.header_string("Return-Path") == "<>" # Some sort of auto-response # Check for Exim’s X-Failed-Recipients header failed_recipients = message.header_string("X-Failed-Recipients") if !failed_recipients.nil? # The X-Failed-Recipients header contains the email address that failed # Check for the words "This is a permanent error." in the body, to indicate # a permanent failure if message.body =~ /This is a permanent error./ return failed_recipients end end return nil end end def not_a_bounce(raw_message) forward_non_bounces_to = MySociety::Config.get("FORWARD_NONBOUNCE_RESPONSES_TO", "user-support@localhost") IO.popen("/usr/sbin/sendmail -i #{forward_non_bounces_to}", "w") do |f| f.write(raw_message); f.close; end end def load_rails require File.join('config', 'boot') require RAILS_ROOT + '/config/environment' end def record_bounce(email_address, bounce_message) User.record_bounce_for_email(email_address, bounce_message) end main