diff --git a/CHANGELOG.md b/CHANGELOG.md index c49a6a91..1d31bbf3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. ### Improvements - Load settings from environment variables +- Add "List-Unsubscribe" header to alert and report emails ## 1.2.0 - 2018-10-20 diff --git a/hc/accounts/models.py b/hc/accounts/models.py index e3ff53b0..869a542b 100644 --- a/hc/accounts/models.py +++ b/hc/accounts/models.py @@ -150,18 +150,21 @@ class Profile(models.Model): # rendering the template checks = list(checks) + unsub_url = self.reports_unsub_url() + + headers = {"List-Unsubscribe": unsub_url} ctx = { "checks": checks, "sort": self.sort, "now": timezone.now(), - "unsub_link": self.reports_unsub_url(), + "unsub_link": unsub_url, "notifications_url": self.notifications_url(), "nag": nag, "nag_period": self.nag_period.total_seconds(), "num_down": num_down } - emails.report(self.user.email, ctx) + emails.report(self.user.email, ctx, headers) return True def can_invite(self): diff --git a/hc/api/tests/test_notify.py b/hc/api/tests/test_notify.py index e1148ebb..c145f3d5 100644 --- a/hc/api/tests/test_notify.py +++ b/hc/api/tests/test_notify.py @@ -246,6 +246,7 @@ class NotifyTestCase(BaseTestCase): email = mail.outbox[0] self.assertTrue("X-Bounce-Url" in email.extra_headers) + self.assertTrue("List-Unsubscribe" in email.extra_headers) def test_it_skips_unverified_email(self): self._setup_data("email", "alice@example.org", email_verified=False) diff --git a/hc/api/tests/test_sendreports.py b/hc/api/tests/test_sendreports.py index ae5a9cf9..2445b96c 100644 --- a/hc/api/tests/test_sendreports.py +++ b/hc/api/tests/test_sendreports.py @@ -30,7 +30,7 @@ class SendAlertsTestCase(BaseTestCase): def test_it_sends_report(self): cmd = Command() - cmd.stdout = Mock() # silence output to stdout + cmd.stdout = Mock() # silence output to stdout cmd.pause = Mock() # don't pause for 1s found = cmd.handle_one_monthly_report() @@ -40,6 +40,9 @@ class SendAlertsTestCase(BaseTestCase): self.assertTrue(self.profile.next_report_date > now()) self.assertEqual(len(mail.outbox), 1) + email = mail.outbox[0] + self.assertTrue("List-Unsubscribe" in email.extra_headers) + def test_it_obeys_next_report_date(self): self.profile.next_report_date = now() + td(days=1) self.profile.save() diff --git a/hc/api/transports.py b/hc/api/transports.py index 9b10583f..fad1ffd8 100644 --- a/hc/api/transports.py +++ b/hc/api/transports.py @@ -50,7 +50,12 @@ class Email(Transport): if not self.channel.email_verified: return "Email not verified" - headers = {"X-Bounce-Url": bounce_url} + unsub_link = self.channel.get_unsub_link() + + headers = { + "X-Bounce-Url": bounce_url, + "List-Unsubscribe": unsub_link + } try: # Look up the sorting preference for this email address @@ -67,7 +72,7 @@ class Email(Transport): "checks": list(self.checks()), "sort": sort, "now": timezone.now(), - "unsub_link": self.channel.get_unsub_link() + "unsub_link": unsub_link } emails.alert(self.channel.value, ctx, headers) diff --git a/hc/lib/emails.py b/hc/lib/emails.py index 73bcbd83..70efcc47 100644 --- a/hc/lib/emails.py +++ b/hc/lib/emails.py @@ -56,8 +56,8 @@ def verify_email(to, ctx): send("verify-email", to, ctx) -def report(to, ctx): - send("report", to, ctx) +def report(to, ctx, headers={}): + send("report", to, ctx, headers) def invoice(to, ctx, filename, pdf_data): diff --git a/templates/emails/alert-body-html.html b/templates/emails/alert-body-html.html index 3d8dde81..24e506ab 100644 --- a/templates/emails/alert-body-html.html +++ b/templates/emails/alert-body-html.html @@ -18,18 +18,6 @@ Here is a summary of your checks: Thanks,
The {% escaped_site_name %} Team - {% endblock %} {% block unsub %}