aboutsummaryrefslogtreecommitdiffstats
path: root/script/handle-mail-replies
blob: 1f7ca6e2ca3afe63d1674c4016276ea5bf80d246 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#!/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