aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xbin/handlemail37
-rw-r--r--docs/_layouts/page.html1
-rwxr-xr-xdocs/customising/handlemail.md119
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.