diff --git a/CHANGELOG.md b/CHANGELOG.md
index bdb0954d..9302add5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file.
- Add support for OpsGenie EU region (#294)
- Update OpsGenie logo and setup illustrations
- Add a "Create a Copy" function for cloning checks (#288)
+- Send email notification when monthly SMS sending limit is reached (#292)
### Bug Fixes
- Prevent double-clicking the submit button in signup form
diff --git a/hc/accounts/models.py b/hc/accounts/models.py
index 37ed5cd7..57f00aa0 100644
--- a/hc/accounts/models.py
+++ b/hc/accounts/models.py
@@ -109,6 +109,13 @@ class Profile(models.Model):
ctx = {"button_text": "Change Email", "button_url": settings.SITE_ROOT + path}
emails.change_email(self.user.email, ctx)
+ def send_sms_limit_notice(self, transport):
+ ctx = {"transport": transport, "limit": self.sms_limit}
+ if self.sms_limit != 500 and settings.USE_PAYMENTS:
+ ctx["url"] = settings.SITE_ROOT + reverse("hc-billing")
+
+ emails.sms_limit(self.user.email, ctx)
+
def projects(self):
""" Return a queryset of all projects we have access to. """
diff --git a/hc/api/tests/test_notify.py b/hc/api/tests/test_notify.py
index d680feb4..1b7361a0 100644
--- a/hc/api/tests/test_notify.py
+++ b/hc/api/tests/test_notify.py
@@ -591,6 +591,13 @@ class NotifyTestCase(BaseTestCase):
n = Notification.objects.get()
self.assertTrue("Monthly SMS limit exceeded" in n.error)
+ # And email should have been sent
+ self.assertEqual(len(mail.outbox), 1)
+
+ email = mail.outbox[0]
+ self.assertEqual(email.to[0], "alice@example.org")
+ self.assertEqual(email.subject, "Monthly SMS Limit Reached")
+
@patch("hc.api.transports.requests.request")
def test_sms_limit_reset(self, mock_post):
# At limit, but also into a new month
@@ -652,6 +659,13 @@ class NotifyTestCase(BaseTestCase):
n = Notification.objects.get()
self.assertTrue("Monthly message limit exceeded" in n.error)
+ # And email should have been sent
+ self.assertEqual(len(mail.outbox), 1)
+
+ email = mail.outbox[0]
+ self.assertEqual(email.to[0], "alice@example.org")
+ self.assertEqual(email.subject, "Monthly WhatsApp Limit Reached")
+
@patch("apprise.Apprise")
@override_settings(APPRISE_ENABLED=True)
def test_apprise_enabled(self, mock_apprise):
diff --git a/hc/api/transports.py b/hc/api/transports.py
index 74ffcaa2..4c4e177d 100644
--- a/hc/api/transports.py
+++ b/hc/api/transports.py
@@ -412,6 +412,7 @@ class Sms(HttpTransport):
def notify(self, check):
profile = Profile.objects.for_user(self.channel.project.owner)
if not profile.authorize_sms():
+ profile.send_sms_limit_notice("SMS")
return "Monthly SMS limit exceeded"
url = self.URL % settings.TWILIO_ACCOUNT
@@ -439,6 +440,7 @@ class WhatsApp(HttpTransport):
def notify(self, check):
profile = Profile.objects.for_user(self.channel.project.owner)
if not profile.authorize_sms():
+ profile.send_sms_limit_notice("WhatsApp")
return "Monthly message limit exceeded"
url = self.URL % settings.TWILIO_ACCOUNT
diff --git a/hc/lib/emails.py b/hc/lib/emails.py
index 68bd34ae..f0e3a940 100644
--- a/hc/lib/emails.py
+++ b/hc/lib/emails.py
@@ -75,3 +75,7 @@ def invoice(to, ctx, filename, pdf_data):
def deletion_notice(to, ctx, headers={}):
send("deletion-notice", to, ctx, headers)
+
+
+def sms_limit(to, ctx):
+ send("sms-limit", to, ctx)
diff --git a/templates/emails/sms-limit-body-html.html b/templates/emails/sms-limit-body-html.html
new file mode 100644
index 00000000..37710bec
--- /dev/null
+++ b/templates/emails/sms-limit-body-html.html
@@ -0,0 +1,22 @@
+{% extends "emails/base.html" %}
+{% load hc_extras %}
+
+{% block content %}
+Hello,
+
+We could not deliver a {{ transport }} notification because your {% site_name %} +account has reached its monthly sending limit of +{{ limit }} sends per month. The limit resets at the start of +each month. +
+ +{% if url %} +You can increase the monthly sending limit by upgrading your billing plan.
+{% endif %} + +{% endblock %} + +{% block content_more %} +Regards,