diff --git a/aleksis/core/forms.py b/aleksis/core/forms.py
index cef045d867bd838acc8443c17eb695a48e90b31a..48a6e1e9dddd4f30fd4f96ab006f80b262bf37b5 100644
--- a/aleksis/core/forms.py
+++ b/aleksis/core/forms.py
@@ -6,6 +6,30 @@ from django_select2.forms import ModelSelect2MultipleWidget, Select2Widget
 
 from .models import Group, Person, School, SchoolTerm
 
+RECIPIENT_CHOICES = [
+    ('guardians', _('Guardians')),
+    ('group', _('Group members')),
+    ('owners', _('Group owners')),
+]
+
+SERVICE_CHOICES = [
+    ('mail', _('E mail')),
+    ('sms', _('SMS')),
+]
+
+SENDER_CHOICES = [
+    ('self', _('Personally')),
+    ('self_masq', _('Personally (only first name)')),
+    ('org', _('Organisation')),
+]
+
+class GroupContactForm(forms.Form):
+    service = forms.ChoiceField(label=_('Delivery'), choices=SERVICE_CHOICES)
+    sender = forms.ChoiceField(label=_('Sender'), choices=SENDER_CHOICES)
+    recipients = forms.MultipleChoiceField(
+        label=_('Receiver'), choices=RECIPIENT_CHOICES)
+    subject = forms.CharField(label=_('Subject'))
+    text = forms.CharField(label=_('Text'), widget=forms.Textarea)
 
 class PersonAccountForm(forms.ModelForm):
     class Meta:
diff --git a/aleksis/core/templates/core/group_contact.html b/aleksis/core/templates/core/group_contact.html
new file mode 100644
index 0000000000000000000000000000000000000000..f9611f08d1d2b097573ea6114e1c4db2c5c8d16d
--- /dev/null
+++ b/aleksis/core/templates/core/group_contact.html
@@ -0,0 +1,15 @@
+{% extends "core/base.html" %}
+{% load material_form i18n %}
+
+{% block page_title %}{% blocktrans %}Group communication{% endblocktrans %}{% endblock %}
+
+{% block content %}
+ <h4>{{ group.name }} <small class="grey-text">{{ group.short_name }}</small></h4>
+
+ <form method="post">
+  {% csrf_token %}
+  {% form form=group_contact_form %}{% endform %}
+  {% trans "Send" as caption%}
+  {% include "core/save_button.html" with icon="send" caption=caption %}
+ </form>
+{% endblock %}
diff --git a/aleksis/core/templates/core/group_full.html b/aleksis/core/templates/core/group_full.html
index 2b1b9ae3fa10c9e4dfeddb8c151ddd4a7e98d029..626a69dee125bd0bbd1d33dea08cd9911c3950b0 100644
--- a/aleksis/core/templates/core/group_full.html
+++ b/aleksis/core/templates/core/group_full.html
@@ -14,6 +14,10 @@
       <i class="material-icons left">edit</i>
       {% trans "Edit" %}
     </a>
+    <a href="{% url 'contact_group_by_id' group.id %}" class="btn waves-effect waves-light">
+      <i class="material-icons left">send</i>
+      {% trans "Contact" %}
+    </a>
   </p>
 
   <h5>{% blocktrans %}Owners{% endblocktrans %}</h5>
diff --git a/aleksis/core/urls.py b/aleksis/core/urls.py
index 6f1d4275e0fd15f2b1cd315353beb56d219342fd..ef13e4e6296f62d93b599e77edaf66205b727361 100644
--- a/aleksis/core/urls.py
+++ b/aleksis/core/urls.py
@@ -33,6 +33,7 @@ urlpatterns = [
     path("group/create", views.edit_group, name="create_group"),
     path("group/<int:id_>", views.group, name="group_by_id"),
     path("group/<int:id_>/edit", views.edit_group, name="edit_group_by_id"),
+    path("group/<int:id_>/contact", views.group_contact, name="contact_group_by_id"),
     path("", views.index, name="index"),
     path("notifications/mark-read/<int:id_>", views.notification_mark_read, name="notification_mark_read"),
     path("maintenance-mode/", include("maintenance_mode.urls")),
diff --git a/aleksis/core/views.py b/aleksis/core/views.py
index c610ec8abf640246355fd04e56130e15f103f483..23ee8d500326ec6c836215c7193dda058ea6810e 100644
--- a/aleksis/core/views.py
+++ b/aleksis/core/views.py
@@ -2,6 +2,7 @@ from typing import Optional
 
 from django.contrib.auth.decorators import login_required
 from django.core.exceptions import PermissionDenied
+from django.core.mail import EmailMessage
 from django.http import Http404, HttpRequest, HttpResponse
 from django.shortcuts import get_object_or_404, redirect, render
 from django.utils.translation import ugettext_lazy as _
@@ -15,6 +16,7 @@ from .forms import (
     EditSchoolForm,
     EditTermForm,
     PersonsAccountsFormSet,
+    GroupContactForm,
 )
 from .models import Activity, Group, Notification, Person, School, DashboardWidget
 from .tables import GroupsTable, PersonsTable
@@ -264,3 +266,79 @@ def notification_mark_read(request: HttpRequest, id_: int) -> HttpResponse:
         raise PermissionDenied(_("You are not allowed to mark notifications from other users as read!"))
 
     return redirect("index")
+
+@login_required
+def group_contact(request: HttpRequest, id_: int) -> HttpResponse:
+    context = {}
+
+    current_person = Person.objects.get(user=request.user)
+
+    group = get_object_or_404(Group, id=id_)
+    context['group'] = group
+
+    group_contact_form = GroupContactForm()
+
+    if request.method == 'POST':
+        group_contact_form = GroupContactForm(request.POST)
+        if group_contact_form.is_valid():
+            if group_contact_form.cleaned_data['service'] == 'mail':
+                message = EmailMessage()
+
+                if group_contact_form.cleaned_data['sender'] == 'self':
+                    message.from_email = '"%s" <%s>' % (
+                        current_person.full_name, current_person.email)
+                elif group_contact_form.cleaned_data['sender'] == 'self_masq':
+                    message.from_email = '"%s" <%s>' % (
+                        current_person.first_name, settings.MAIL_OUT)
+                elif group_contact_form.cleaned_data['sender'] == 'org':
+                    message.from_email = settings.MAIL_OUT
+
+                message.bcc = []
+                for person in group.members.all():
+                    if 'group' in group_contact_form.cleaned_data['recipients']:
+                        message.bcc.append(person.email)
+                    if 'guardians' in group_contact_form.cleaned_data['recipients']:
+                        for guardian in person.guardians:
+                            message.bcc.append(guardian.email)
+
+                if 'owners' in group_contact_form.cleaned_data['recipients']:
+                    for owner in group.owners.all():
+                        message.bcc.append(owner.email)
+
+                message.subject = group_contact_form.cleaned_data['subject']
+                message.body = group_contact_form.cleaned_data['text']
+
+                message.send()
+            elif group_contact_form.cleaned_data['service'] == 'sms':
+                if group_contact_form.cleaned_data['sender'] == 'self':
+                    sender = current_person.mobile
+                    if not sender:
+                        sender = current_person.first_name[:11]
+                elif group_contact_form.cleaned_data['sender'] == 'self_masq':
+                    sender = current_person.first_name[:11]
+                elif group_contact_form.cleaned_data['sender'] == 'org':
+                    sender = settings.SITE_TITLE
+
+                to = []
+                for person in group.members.all():
+                    if 'group' in group_contact_form.cleaned_data['recipients']:
+                        to.append(person.mobile_number)
+                    if 'guardians' in group_contact_form.cleaned_data['recipients']:
+                        for guardian in person.guardians:
+                            to.append(guardian.mobile_number)
+
+                if 'owners' in group_contact_form.cleaned_data['recipients']:
+                    for owner in group.owners.all():
+                        to.append(owner.mobile_number)
+
+                msg = group_contact_form.cleaned_data['text']
+
+                ret = send_sms(sender, to, msg)
+                if ret.status_code != 200:
+                    context['error'] = _(
+                        'SMS could not be transmitted to provider.')
+            return redirect('group_by_id', id_=id_)
+
+    context['group_contact_form'] = group_contact_form
+
+    return render(request, 'core/group_contact.html', context)