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 %}