diff --git a/tests/push/test_email.py b/tests/push/test_email.py
index 4b5c96aeae..73a430ddc6 100644
--- a/tests/push/test_email.py
+++ b/tests/push/test_email.py
@@ -13,10 +13,12 @@
# limitations under the License.
import email.message
import os
+from http import HTTPStatus
from typing import Any, Dict, List, Sequence, Tuple
import attr
import pkg_resources
+from parameterized import parameterized
from twisted.internet.defer import Deferred
from twisted.test.proto_helpers import MemoryReactor
@@ -25,9 +27,11 @@ import synapse.rest.admin
from synapse.api.errors import Codes, SynapseError
from synapse.push.emailpusher import EmailPusher
from synapse.rest.client import login, room
+from synapse.rest.synapse.client.unsubscribe import UnsubscribeResource
from synapse.server import HomeServer
from synapse.util import Clock
+from tests.server import FakeSite, make_request
from tests.unittest import HomeserverTestCase
@@ -175,6 +179,57 @@ class EmailPusherTests(HomeserverTestCase):
self._check_for_mail()
+ @parameterized.expand([(False,), (True,)])
+ def test_unsubscribe(self, use_post: bool) -> None:
+ # Create a simple room with two users
+ room = self.helper.create_room_as(self.user_id, tok=self.access_token)
+ self.helper.invite(
+ room=room, src=self.user_id, tok=self.access_token, targ=self.others[0].id
+ )
+ self.helper.join(room=room, user=self.others[0].id, tok=self.others[0].token)
+
+ # The other user sends a single message.
+ self.helper.send(room, body="Hi!", tok=self.others[0].token)
+
+ # We should get emailed about that message
+ args, kwargs = self._check_for_mail()
+
+ # That email should contain an unsubscribe link in the body and header.
+ msg: bytes = args[5]
+
+ # Multipart: plain text, base 64 encoded; html, base 64 encoded
+ multipart_msg = email.message_from_bytes(msg)
+ txt = multipart_msg.get_payload()[0].get_payload(decode=True).decode()
+ html = multipart_msg.get_payload()[1].get_payload(decode=True).decode()
+ self.assertIn("/_synapse/client/unsubscribe", txt)
+ self.assertIn("/_synapse/client/unsubscribe", html)
+
+ # The unsubscribe headers should exist.
+ assert multipart_msg.get("List-Unsubscribe") is not None
+ self.assertIsNotNone(multipart_msg.get("List-Unsubscribe-Post"))
+
+ # Open the unsubscribe link.
+ unsubscribe_link = multipart_msg["List-Unsubscribe"].strip("<>")
+ unsubscribe_resource = UnsubscribeResource(self.hs)
+ channel = make_request(
+ self.reactor,
+ FakeSite(unsubscribe_resource, self.reactor),
+ "POST" if use_post else "GET",
+ unsubscribe_link,
+ shorthand=False,
+ )
+ self.assertEqual(HTTPStatus.OK, channel.code, channel.result)
+
+ # Ensure the pusher was removed.
+ pushers = list(
+ self.get_success(
+ self.hs.get_datastores().main.get_pushers_by(
+ {"user_name": self.user_id}
+ )
+ )
+ )
+ self.assertEqual(pushers, [])
+
def test_invite_sends_email(self) -> None:
# Create a room and invite the user to it
room = self.helper.create_room_as(self.others[0].id, tok=self.others[0].token)
|