diff options
Diffstat (limited to 'script/handle-mail-replies')
-rwxr-xr-x | script/handle-mail-replies | 92 |
1 files changed, 76 insertions, 16 deletions
diff --git a/script/handle-mail-replies b/script/handle-mail-replies index 5762ddd31..93cdc8cfd 100755 --- a/script/handle-mail-replies +++ b/script/handle-mail-replies @@ -17,20 +17,37 @@ load "config.rb" MySociety::Config.set_file(File.join($alaveteli_dir, 'config', 'general'), true) MySociety::Config.load_default -def main - 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) +def main(in_test_mode) + Dir.chdir($alaveteli_dir) do + load_rails + + raw_message = $stdin.read + message = TMail::Mail.parse(raw_message) + + pfas = permanently_failed_addresses(message) + if !pfas.empty? + if in_test_mode + puts pfas + else + pfas.each do |pfa| + record_bounce(pfa, raw_message) + end + end + return 1 + end + + if is_oof? message + # Discard out-of-office messages + return 2 + end + + # Otherwise forward the message on + forward_on(raw_message) unless in_test_mode + return 0 end end -def permanently_failed_address(raw_message) - message = TMail::Mail.parse(raw_message) - +def permanently_failed_addresses(message) if message.header_string("Return-Path") == "<>" # Some sort of auto-response @@ -41,14 +58,55 @@ def permanently_failed_address(raw_message) # 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 + return failed_recipients.split(/,\s*/) end end - return nil + + # Next, look for multipart/report + if message.content_type == "multipart/report" + permanently_failed_recipients = [] + message.parts.each do |part| + if part.content_type == "message/delivery-status" + sections = part.body.split(/\r?\n\r?\n/) + # The first section is a generic header; subsequent sections + # represent a particular recipient. Since we + sections[1..-1].each do |section| + if section !~ /^Status: (\d)/ || $1 != '5' + # Either we couldn’t find the Status field, or it was a transient failure + break + end + if section =~ /^Final-Recipient: rfc822;(.+)/ + permanently_failed_recipients.push($1) + end + end + end + end + if !permanently_failed_recipients.empty? + return permanently_failed_recipients + end + end + end + + return [] +end + +def is_oof?(message) + # Check for out-of-office + + if message.header_string("Return-Path") == "<>" + subject = message.header_string("Subject") + if subject.start_with? "Out of Office: " + return true + end + if subject.start_with? "Automatic reply: " + return true + end end + + return false end -def not_a_bounce(raw_message) +def forward_on(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); @@ -57,7 +115,7 @@ def not_a_bounce(raw_message) end def load_rails - require File.join($alaveteli_dir, 'config', 'boot') + require File.join('config', 'boot') require RAILS_ROOT + '/config/environment' end @@ -65,4 +123,6 @@ def record_bounce(email_address, bounce_message) User.record_bounce_for_email(email_address, bounce_message) end -main +in_test_mode = (ARGV[0] == "--test") +status = main(in_test_mode) +exit(status) if in_test_mode |