diff --git a/apimail/api/views.py b/apimail/api/views.py
index 8f64b915b65005fd3e7e7c021bc07dac0cb117dc..f5b06b66be60efa102a0f53bad2bdc3137726b5b 100644
--- a/apimail/api/views.py
+++ b/apimail/api/views.py
@@ -32,7 +32,9 @@ class StoredMessageListAPIView(ListAPIView):
 
 
 class StoredMessageRetrieveAPIView(RetrieveAPIView):
-    queryset = StoredMessage.objects.all()
     permission_classes = (IsAdminUser,)
     serializer_class = StoredMessageSerializer
     lookup_field = 'uuid'
+
+    def get_queryset(self):
+        return StoredMessage.objects.filter_for_user(self.request.user)
diff --git a/apimail/managers.py b/apimail/managers.py
new file mode 100644
index 0000000000000000000000000000000000000000..63e1eac127c75cbb92b66ab8bb90b9d6d0c16507
--- /dev/null
+++ b/apimail/managers.py
@@ -0,0 +1,37 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+from django.db import models
+
+
+class StoredMessageQuerySet(models.QuerySet):
+    """
+    All StoredMessage querysets are always filtered for the user.
+    """
+    def filter_for_user(self, request):
+        """
+        Either su or staff, or user's email addresses overlap with sender/recipients.
+        """
+        if not request.user.is_authenticated:
+            return self.none()
+        elif request.user.is_superuser or request.user.is_admin:
+            return self
+        emails = [request.user.email,] if request.user.email else []
+        if request.user.contributor:
+            for pe in request.user.contributor.profile.emails.all():
+                emails.append(pe.email)
+        return self.filter_for_emails(emails=emails)
+
+    def filter_for_emails(self, emails):
+        """
+        Ensure overlap of the emails in emails kwarg with those in sender or recipients.
+        """
+        emails_used = emails
+        if not isinstance(emails, list):
+            emails_used = [emails]
+        emails_lower = [e.lower() for e in emails_used]
+        return self.filter(
+            models.Q(data__sender__in=emails_lower) |
+            models.Q(data__recipients__in=emails_lower) | # if recipients is a single entry
+            models.Q(data__recipients__overlap=emails_lower)) # if recipients is a list
diff --git a/apimail/models/stored_message.py b/apimail/models/stored_message.py
index f3e1bf8958cdce113ed61104c2149023d31a42f1..1f5e01b9a7efc9db0497d8a11f114a5f76d8923b 100644
--- a/apimail/models/stored_message.py
+++ b/apimail/models/stored_message.py
@@ -10,6 +10,7 @@ from django.urls import reverse
 
 from scipost.storage import SecureFileStorage
 
+from ..managers import StoredMessageQuerySet
 from ..validators import validate_max_email_attachment_file_size
 
 
@@ -23,6 +24,8 @@ class StoredMessage(models.Model):
         editable=False)
     data = JSONField(default=dict)
 
+    objects = StoredMessageQuerySet.as_manager()
+
     class Meta:
         ordering = ['-data__Date',]