diff --git a/src/core/admin.py b/src/core/admin.py
index 68a2c7c438c68ab8ac99c68e402f9a347be7caa4..25820722a152a4b7067e448c8d6bed2b0526eb63 100644
--- a/src/core/admin.py
+++ b/src/core/admin.py
@@ -6,6 +6,7 @@ from django.utils.translation import gettext_lazy as _
 
 from .models import \
     Conference, ConferenceMember, ConferenceTag, ConferenceTrack, \
+    DirectMessage, \
     Event, EventAttachment, EventParticipant, \
     PlatformUser, \
     Room, RoomLink, \
@@ -160,6 +161,13 @@ class ConferenceTagAdmin(admin.ModelAdmin):
     search_fields = ['slug', 'description']
 
 
+class DirectMessageAdmin(admin.ModelAdmin):
+    list_display = ['conference', 'timestamp', 'sender', 'recipient', 'subject', 'deleted_by_sender', 'deleted_by_recipient', 'flagged_for_abuse']
+    list_display_links = ['timestamp']
+    search_fields = ['sender', 'recipient', 'subject']
+    readonly_fields = ['timestamp', 'sender', 'recipient', 'in_reply_to', 'deleted_by_sender', 'subject', 'body']
+
+
 class TagsInline(GenericTabularInline):
     model = TagItem
     ct_field = 'target_type'
@@ -461,6 +469,7 @@ admin.site.register(Conference, ConferenceAdmin)
 admin.site.register(ConferenceMember, ConferenceMemberAdmin)
 admin.site.register(ConferenceTag, ConferenceTagAdmin)
 admin.site.register(ConferenceTrack, ConferenceTrackAdmin)
+admin.site.register(DirectMessage, DirectMessageAdmin)
 admin.site.register(Assembly, AssemblyAdmin)
 admin.site.register(Event, EventAdmin)
 admin.site.register(Room, RoomAdmin)
diff --git a/src/core/locale/de/LC_MESSAGES/django.po b/src/core/locale/de/LC_MESSAGES/django.po
index 936e656c0c45a3ca1badd9de8c41d9af534f2282..c706c6d1263ae6e9850b1a1cf65965e8134758f7 100644
--- a/src/core/locale/de/LC_MESSAGES/django.po
+++ b/src/core/locale/de/LC_MESSAGES/django.po
@@ -375,6 +375,18 @@ msgstr "Zeitzone in der die Konfernez veranstaltet wird"
 msgid "Conference__timezone"
 msgstr "Zeitzone"
 
+msgid "Conference__send_pn_disabled__help"
+msgstr "PN-Versand in dieser Konferenz deaktivieren"
+
+msgid "Conference__send_pn_disabled"
+msgstr "PNs deaktiviert"
+
+msgid "Conference__board_disabled__help"
+msgstr "Einträge im Board erstellen / bearbeiten deaktiviert"
+
+msgid "Conference__board_disabled"
+msgstr "Bulletin Board deaktiviert"
+
 msgid "Conference__support_clusters__help"
 msgstr "Assemblies können sich zu Clustern gruppieren"
 
@@ -1095,6 +1107,12 @@ msgstr "im WorkAdventure wird Video von anderen Teilnehmern gezeigt"
 msgid "PlatformUser__receive_video"
 msgstr "Video-Chat"
 
+msgid "PlatformUser__shadow_banned__help"
+msgstr "User kann PNs verschicken aber die Empfänger werden diese nie zu sehen bekommen"
+
+msgid "PlatformUser__shadow_banned"
+msgstr "Shadowbanned"
+
 msgid "PlatformUser__autoaccept_contacts__help"
 msgstr "Kontaktanfragen automatisch akzeptieren"
 
diff --git a/src/core/locale/en/LC_MESSAGES/django.po b/src/core/locale/en/LC_MESSAGES/django.po
index 7037487469959983ca8f0ba7da1935ff3c512554..ab9303974afc4609226cd3b6f21d3e05569828c9 100644
--- a/src/core/locale/en/LC_MESSAGES/django.po
+++ b/src/core/locale/en/LC_MESSAGES/django.po
@@ -381,6 +381,18 @@ msgstr "time zone in which this conference is operated"
 msgid "Conference__timezone"
 msgstr "time zone"
 
+msgid "Conference__send_pn_disabled__help"
+msgstr "disable sending of private messages in this conference"
+
+msgid "Conference__send_pn_disabled"
+msgstr "disable PMs"
+
+msgid "Conference__board_disabled__help"
+msgstr "creating / editing board entries disabled"
+
+msgid "Conference__board_disabled"
+msgstr "disable bulletin board"
+
 msgid "Conference__support_clusters__help"
 msgstr "allow assemblies to cluster in groups"
 
@@ -1101,6 +1113,12 @@ msgstr "see video from other participants in e.g. WorkAdventure"
 msgid "PlatformUser__receive_video"
 msgstr "video chat"
 
+msgid "PlatformUser__shadow_banned__help"
+msgstr "User will be able to send DMs but recipients won't see them"
+
+msgid "PlatformUser__shadow_banned"
+msgstr "shadow banned"
+
 msgid "PlatformUser__autoaccept_contacts__help"
 msgstr "automatically accept incoming contact requests"
 
diff --git a/src/core/migrations/0055_dm_restrictions.py b/src/core/migrations/0055_dm_restrictions.py
new file mode 100644
index 0000000000000000000000000000000000000000..e898a9e2bafa5156d65afb7785ed830a9b1afeb3
--- /dev/null
+++ b/src/core/migrations/0055_dm_restrictions.py
@@ -0,0 +1,28 @@
+# Generated by Django 3.1.4 on 2020-12-29 00:05
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('core', '0054_UserBadgeGrammar'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='conference',
+            name='board_disabled',
+            field=models.BooleanField(default=False, help_text='Conference__board_disabled__help', verbose_name='Conference__board_disabled'),
+        ),
+        migrations.AddField(
+            model_name='conference',
+            name='send_pn_disabled',
+            field=models.BooleanField(default=False, help_text='Conference__send_pn_disabled__help', verbose_name='Conference__send_pn_disabled'),
+        ),
+        migrations.AddField(
+            model_name='platformuser',
+            name='shadow_banned',
+            field=models.BooleanField(default=False, help_text='PlatformUser__shadow_banned__help', verbose_name='PlatformUser__shadow_banned'),
+        ),
+    ]
diff --git a/src/core/models/conference.py b/src/core/models/conference.py
index 773a09b1e4a4e9d0fb5387147fdf9b95569c7885..9aaa624897f54ad5489b48205e9a4bdfed51300f 100644
--- a/src/core/models/conference.py
+++ b/src/core/models/conference.py
@@ -159,6 +159,15 @@ class Conference(models.Model):
         help_text=_('Conference__timezone__help'),
         verbose_name=_('Conference__timezone'))
 
+    send_pn_disabled = models.BooleanField(
+        default=False,
+        help_text=_('Conference__send_pn_disabled__help'),
+        verbose_name=_('Conference__send_pn_disabled'))
+    board_disabled = models.BooleanField(
+        default=False,
+        help_text=_('Conference__board_disabled__help'),
+        verbose_name=_('Conference__board_disabled'))
+
     support_clusters = models.BooleanField(
         default=True,
         help_text=_('Conference__support_clusters__help'),
diff --git a/src/core/models/users.py b/src/core/models/users.py
index 88b362e36b073bd636bde48e19e5da5af06aaa25..e11667e6f8d99217ad924bbedead48b49b073b1c 100644
--- a/src/core/models/users.py
+++ b/src/core/models/users.py
@@ -114,6 +114,12 @@ class PlatformUser(AbstractUser):
         help_text=_('PlatformUser__receive_video__help'),
         verbose_name=_('PlatformUser__receive_video'))
 
+    # Administrative
+    shadow_banned = models.BooleanField(
+        default=False,
+        help_text=_('PlatformUser__shadow_banned__help'),
+        verbose_name=_('PlatformUser__shadow_banned'))
+
     audio_muted = models.BooleanField(default=False)
     audio_volume = models.FloatField(blank=True, null=True)
 
diff --git a/src/plainui/forms.py b/src/plainui/forms.py
index 3a91ebcc548fa04e793ef36b3496677bd0e077c3..f63b56dbbaf4765e1cc7fd8badda0da509d3e195 100644
--- a/src/plainui/forms.py
+++ b/src/plainui/forms.py
@@ -25,17 +25,35 @@ class UsernameField(forms.CharField):
 
 
 class NewDirectMessageForm(forms.Form):
+    def __init__(self, conf, user, *args, **kwargs):
+        self.conf = conf
+        self.user = user
+        super().__init__(*args, **kwargs)
+
     in_reply_to = forms.UUIDField(required=False)
     recipient = UsernameField(widget=forms.TextInput(attrs={'placeholder': _("Please enter the recipient name")}))
     subject = forms.CharField(max_length=200, min_length=1, strip=True, widget=forms.TextInput(attrs={'placeholder': _("Please enter a subject")}))
     body = forms.CharField(widget=forms.Textarea)
 
+    def clean(self):
+        if self.conf.send_pn_disabled:
+            raise ValidationError(_("Sending Messages is currenly disabled"))
+
 
 class BulletinBoardEntryForm(forms.Form):
+    def __init__(self, conf, user, *args, **kwargs):
+        self.conf = conf
+        self.user = user
+        super().__init__(*args, **kwargs)
+
     title = forms.CharField(max_length=200, min_length=1, strip=True, widget=forms.TextInput(attrs={'placeholder': _("Please enter a title")}))
     is_public = forms.BooleanField(required=False)
     text = forms.CharField(widget=forms.Textarea)
 
+    def clean(self):
+        if self.conf.board_disabled:
+            raise ValidationError(_("Bulletin Board is currenly disabled"))
+
 
 class ExampleForm(forms.Form):
     """ used in the component gallery """
diff --git a/src/plainui/locale/de/LC_MESSAGES/django.po b/src/plainui/locale/de/LC_MESSAGES/django.po
index 08786f946453bef2ce15d44fa19fc0e7860ad028..f72c3dd8b5041ee9b00119b2bb58002074af77a8 100644
--- a/src/plainui/locale/de/LC_MESSAGES/django.po
+++ b/src/plainui/locale/de/LC_MESSAGES/django.po
@@ -27,9 +27,15 @@ msgstr "Bitte einen Empfänger angeben"
 msgid "Please enter a subject"
 msgstr "Bitte einen Betreff eingeben"
 
+msgid "Sending Messages is currenly disabled"
+msgstr "Nachrichten versenden ist momentan deaktiviert"
+
 msgid "Please enter a title"
 msgstr "Bitte einen Titel eingeben"
 
+msgid "Bulletin Board is currenly disabled"
+msgstr "Das Board ist momentan deaktiviert"
+
 msgid "Placeholder text"
 msgstr "Platzhalter text"
 
diff --git a/src/plainui/locale/en/LC_MESSAGES/django.po b/src/plainui/locale/en/LC_MESSAGES/django.po
index 398c56773becf3cfdbb597c840e8854e86e151bd..a0488d7769bc9b9d27e9bd0c213abc1a99a43bc0 100644
--- a/src/plainui/locale/en/LC_MESSAGES/django.po
+++ b/src/plainui/locale/en/LC_MESSAGES/django.po
@@ -27,9 +27,15 @@ msgstr ""
 msgid "Please enter a subject"
 msgstr ""
 
+msgid "Sending Messages is currenly disabled"
+msgstr ""
+
 msgid "Please enter a title"
 msgstr ""
 
+msgid "Bulletin Board is currenly disabled"
+msgstr ""
+
 msgid "Placeholder text"
 msgstr ""
 
diff --git a/src/plainui/views.py b/src/plainui/views.py
index a426f9dd2113e1439d24ad8743e902b995f07bb0..0c0a6922ce1336f086683d480ffbaabcd5b496a9 100644
--- a/src/plainui/views.py
+++ b/src/plainui/views.py
@@ -827,6 +827,12 @@ class PersonalMessageSendView(ConferenceRequiredMixin, FormView):
         initial['in_reply_to'] = self.request.POST.get('in_reply_to', self.request.GET.get('in_reply_to', ''))
         return initial
 
+    def get_form_kwargs(self):
+        kwargs = super().get_form_kwargs()
+        kwargs['conf'] = self.conf
+        kwargs['user'] = self.request.user
+        return kwargs
+
     def get_success_url(self):
         return reverse('plainui:personal_message', kwargs={'conf_slug': self.kwargs['conf_slug']})
 
@@ -840,6 +846,7 @@ class PersonalMessageSendView(ConferenceRequiredMixin, FormView):
             in_reply_to_id=in_reply_to,
             subject=form.cleaned_data['subject'],
             body=form.cleaned_data['body'],
+            deleted_by_recipient=self.request.user != form.cleaned_data['recipient'] and self.request.user.shadow_banned,
         )
         dm.save()
         if in_reply_to:
@@ -1073,6 +1080,12 @@ class BoardEntryEditView(ConferenceRequiredMixin, FormView):
             **kwargs
         )
 
+    def get_form_kwargs(self):
+        kwargs = super().get_form_kwargs()
+        kwargs['conf'] = self.conf
+        kwargs['user'] = self.request.user
+        return kwargs
+
     def get_initial(self):
         initial = super().get_initial()
         if 'id' in self.kwargs: