diff options
author | Matthew Somerville <matthew-github@dracos.co.uk> | 2018-12-03 09:45:54 +0000 |
---|---|---|
committer | Matthew Somerville <matthew-github@dracos.co.uk> | 2018-12-03 09:45:54 +0000 |
commit | d9f56a0556c1725f9787ad009d527057a4f608d2 (patch) | |
tree | 49cc7c5c97e0362d2382d55f949d1766214cc5ce | |
parent | 916b377b1648dfcf94dd257e4b5fdbfc1acdf107 (diff) | |
parent | f240a3447033e037559ae117f7514ddd88d5902a (diff) |
Merge branch 'joe/2331-handlemail-cobrand'
-rwxr-xr-x | bin/handlemail | 37 | ||||
-rw-r--r-- | docs/_layouts/page.html | 1 | ||||
-rwxr-xr-x | docs/customising/handlemail.md | 119 |
3 files changed, 148 insertions, 9 deletions
diff --git a/bin/handlemail b/bin/handlemail index 5a4d6e1f2..38f5cf41d 100755 --- a/bin/handlemail +++ b/bin/handlemail @@ -19,6 +19,8 @@ BEGIN { require "$d/../setenv.pl"; } +use Getopt::Long; +use Path::Tiny; use FixMyStreet; use FixMyStreet::DB; use FixMyStreet::Email; @@ -29,6 +31,15 @@ use mySociety::SystemMisc qw(print_log); # messages being generated (only in response to non-bounce input, obviously). mySociety::SystemMisc::log_to_stderr(0); +my $cobrand = "default"; + +# Where to forward mail that should be looked at by a person, +# such as a permanent bounce for a report. +my $bouncemgr = FixMyStreet->config('CONTACT_EMAIL'); + +GetOptions ("cobrand=s" => \$cobrand, + "bouncemgr=s" => \$bouncemgr); + my %data = mySociety::HandleMail::get_message(); my @lines = @{$data{lines}}; my $token = get_envelope_token(); @@ -103,14 +114,22 @@ sub handle_permanent_bounce { $object->disable(); } elsif ($type eq 'report') { print_log('info', "Received bounce for report " . $object->id . ", forwarding to support"); - forward_on_to(FixMyStreet->config('CONTACT_EMAIL')); + forward_on_to($bouncemgr); } } sub is_out_of_office { my (%attributes) = @_; return 1 if $attributes{problem} && $attributes{problem} == mySociety::HandleMail::ERR_OUT_OF_OFFICE; - my $subject = $data{message}->head()->get("Subject"); + my $head = $data{message}->head(); + return 1 if $head->get('X-Autoreply') || $head->get('X-Autorespond'); + my $mc = $head->get('X-POST-MessageClass') || ''; + return 1 if $mc eq '9; Autoresponder'; + my $auto_submitted = $head->get("Auto-Submitted") || ''; + return 1 if $auto_submitted && $auto_submitted !~ /no/; + my $precedence = $head->get("Precedence") || ''; + return 1 if $precedence =~ /auto_reply/; + my $subject = $head->get("Subject"); return 1 if $subject =~ /Auto(matic|mated)?[ -_]?(reply|response|responder)|Thank[ _]you[ _]for[ _](your[ _]email|contacting)|Out of (the )?Office|away from the office|This office is closed until|^Re: (Problem Report|New updates)|^Auto: |^E-Mail Response$|^Message Received:|have received your email|Acknowledgement of your email|away from my desk/i; return 0; } @@ -135,7 +154,7 @@ sub handle_bounce_to_verp_address { handle_non_bounce_to_verp_address(); } elsif (!$info) { print_log('info', "Unparsed bounce received for $type " . $object->id . ", forwarding to support"); - forward_on_to(FixMyStreet->config('CONTACT_EMAIL')); + forward_on_to($bouncemgr); } else { print_log('info', "Ignoring bounce received for $type " . $object->id . $info); } @@ -144,7 +163,7 @@ sub handle_bounce_to_verp_address { sub handle_non_bounce_to_verp_address { if ($type eq 'alert' && !is_out_of_office()) { print_log('info', "Received non-bounce for alert " . $object->id . ", forwarding to support"); - forward_on_to(FixMyStreet->config('CONTACT_EMAIL')); + forward_on_to($bouncemgr); } elsif ($type eq 'report') { print_log('info', "Received non-bounce for report " . $object->id . ", forwarding to report creator"); forward_on_to($object->user->email); @@ -160,15 +179,15 @@ sub handle_non_bounce_to_null_address { # Send an automatic response print_log('info', "Received non-bounce to null address, auto-replying"); - my $template = 'reply-autoresponse'; - my $fp = FixMyStreet->path_to("templates", "email", "default", $template)->open or exit 75; - $template = join('', <$fp>); - $fp->close; + + my $template = path(FixMyStreet->path_to("templates", "email", $cobrand, 'reply-autoresponse'))->slurp_utf8; # We generate this as a bounce. my ($rp) = $data{return_path} =~ /^\s*<(.*)>\s*$/; my $mail = FixMyStreet::Email::construct_email({ - From => [ FixMyStreet->config('CONTACT_EMAIL'), 'FixMyStreet' ], + 'Auto-Submitted' => 'auto-replied', + From => [ FixMyStreet->config('CONTACT_EMAIL'), + FixMyStreet->config('CONTACT_NAME') ], To => $rp, _body_ => $template, }); diff --git a/docs/_layouts/page.html b/docs/_layouts/page.html index 9f26312ae..5fcf10df7 100644 --- a/docs/_layouts/page.html +++ b/docs/_layouts/page.html @@ -79,6 +79,7 @@ layout: default <li><a href='{{ "/customising/static-pages/" | relative_url }}'>Static pages</a></li> <li><a href='{{ "/customising/send_reports/" | relative_url }}'>Sending reports</a></li> <li><a href='{{ "/customising/integration/" | relative_url }}'>Back-end integration</a></li> + <li><a href='{{ "/customising/handlemail/" | relative_url }}'>Email bounces</a></li> <li><a href='{{ "/feeding-back/" | relative_url }}'>Feeding back changes</a></li> </ul> </li> diff --git a/docs/customising/handlemail.md b/docs/customising/handlemail.md new file mode 100755 index 000000000..b037bef09 --- /dev/null +++ b/docs/customising/handlemail.md @@ -0,0 +1,119 @@ +--- +layout: page +title: Email bounces +--- + +# Handling email bounces + +<p class="lead"> +Sometimes an email sent from FixMyStreet bounces, perhaps because the contact +address for the responsible body is no longer correct. In order for your site +administrator to notice this, you can configure your system to use the +<code>handlemail</code> script. +</p> + +## What `handlemail` does + +Emails sent to a body when a report is created use something called VERP. +Basically this means that if the email bounces, it will be returned to a unique +address which includes the report ID, so we can figure out which report needs +to be re-sent and which contact address needs to be updated. Alerts use VERP +return paths as well, so we can unsubscribe an email address from further alerts. + +All email sent to one of these VERP addresses should be handled by the +`handlemail` script. In addition to this, `handlemail` can also handle email +sent to the `DO_NOT_REPLY_EMAIL` address. + +The list below describes what `handlemail` will do with these emails. + +1. If an actual email (not a bounce) to the DO-NOT-REPLY address: + + 1. If it looks like an out-of-office message, do nothing. + 1. Send an automatic reply (as a bounce) back to that email saying it is an + unmonitored account (using the `reply-autoresponse` template) + +1. If an actual email (not a bounce) to a VERP address (report submission/alert + email): + + 1. If a reply to an alert email and not out-of-office, forward to the + contact email (defaults to `CONTACT_EMAIL`). + 1. If a reply to a report email, forward on to the report creator + +1. If a bounce message to the DO-NOT-REPLY address, ignore it. + +1. If a bounce message to a VERP address: + + 1. If it looks like a permanent bounce (5xx error but not 5.2.2 mailbox + full), unsubscribe the alert (alert bounce), or forward on to + the contact email (report bounce). + 1. Otherwise, if it looks like an out-of-office, treat as an actual email + (step 2) + 1. Or if unparseable, forward on to the contact email. + 1. Otherwise, ignore the bounce. + +## Configuring `handlemail` + +The `handlemail` script should be run by the same user that runs the FixMyStreet +web service (typically user fms). To configure this, add a line like this to +that user's .forward file: + +``` +"|/var/www/fixmystreet/bin/handlemail" +``` + +The .forward file should be created in the fms user's home directory. Include +the quotes (`"`) and leading pipe (`|`) character, which specify that the email +should be handled by a program. + +Just make sure to set the path to where you have your clone of the fixmystreet + repository. You can also specify a cobrand: + +``` +"|/var/www/fixmystreet/bin/handlemail --cobrand=moon" +``` + +The reply-autoresponse template used for emails sent to the DO-NOT-REPLY address + will then use the template for that cobrand. + +By default `handlemail` uses `CONTACT_EMAIL` as its contact email, but you can +override this by specifying an email in the command line with the `--bouncemgr` +argument. + +If the fms user is running cron jobs, error messages from those jobs are +typically sent to the fms user. To avoid sending those to `handlemail`, you +might want to update the crontab for the fms user by adding a `MAILTO` +directive, such as: + +``` +MAILTO=support@fixmymoon.org +``` + +Finally, you'll need to make sure that email sent to the VERP addresses and to +the DO-NOT-REPLY address is routed to the fms user. This will be different +depending on how you've configured your email server, but if you're using +Postfix you can do this with a virtual alias table. + +### Postfix example configuration + +In your main.cf (typically /etc/postfix/main.cf), add a regexp table to the +virtual_alias_map setting: + +``` +virtual_alias_maps = regexp:/etc/postfix/virtual.regexp +``` + +Then create the virtual.regexp file and add a rule for routing any email +starting with fms- to the fms user: + +``` +/^fms-/ fms +``` +Before this file can be used by postfix it needs to be compiled: + +``` +postmap /etc/postfix/virtual.regexp +``` +The Postfix service needs to be restarted since main.cf was modified. + +Finally, set the `DO_NOT_REPLY_EMAIL` setting in conf/general.yml to +`fms-DO-NOT-REPLY@\<yourdomain\>` so those emails also match the rule. |