diff --git a/models/database.py b/models/database.py
index 2e709c69753b730586a725221327d1a7f4a0fa64..561b14c4e61b843ec878c8e1aacd068203c0c03e 100644
--- a/models/database.py
+++ b/models/database.py
@@ -2,6 +2,7 @@ from flask import render_template, send_file, url_for, redirect, flash, request
 
 from datetime import datetime, time, date, timedelta
 import math
+from io import StringIO, BytesIO
 
 from shared import db
 from utils import random_string, url_manager, get_etherpad_url
@@ -104,8 +105,6 @@ class ProtocolType(db.Model):
             if protocoltype.has_private_view_right(user)
         ]
 
-
-
 class Protocol(db.Model):
     __tablename__ = "protocols"
     id = db.Column(db.Integer, primary_key=True)
@@ -283,6 +282,10 @@ class Document(db.Model):
     def get_filename(self):
         return os.path.join(config.DOCUMENTS_PATH, self.filename)
 
+    def as_file_like(self):
+        with open(self.get_filename(), "rb") as file:
+            return BytesIO(file.read())
+
 @event.listens_for(Document, "before_delete")
 def on_document_delete(mapper, connection, document):
     if document.filename is not None:
diff --git a/server.py b/server.py
index 203d9dd160f586a7e750c2764174f0c20e5c367e..0379c89f97180785e9de09399d063c28f38c510d 100755
--- a/server.py
+++ b/server.py
@@ -565,6 +565,19 @@ def update_protocol(protocol_id):
         return redirect(request.args.get("next") or url_for("show_protocol", protocol_id=protocol.id))
     return render_template("protocol-update.html", upload_form=upload_form, edit_form=edit_form, protocol=protocol)
 
+@app.route("/prococol/send/<int:protocol_id>")
+@login_required
+def send_protocol(protocol_id):
+    user = current_user()
+    protocol = Protocol.query.filter_by(id=protocol_id).first()
+    if protocol is None or not protocol.protocoltype.has_modify_right(user):
+        flash("Invalides Protokoll oder keine Berechtigung.", "alert-error")
+        return redirect(request.args.get("next") or url_for("index"))
+    tasks.send_protocol(protocol)
+    flash("Das Protokoll wurde versandt.", "alert-success")
+    return redirect(request.args.get("next") or url_for("show_protocol", protocol_id=protocol.id))
+    
+
 @app.route("/protocol/tops/new/<int:protocol_id>", methods=["GET", "POST"])
 @login_required
 def new_top(protocol_id):
@@ -738,9 +751,7 @@ def download_document(document_id):
             and not document.protocol.protocoltype.has_public_view_right(user))):
         flash("Keine Berechtigung.", "alert-error")
         return redirect(request.args.get("next") or url_for("index"))
-    with open(document.get_filename(), "rb") as file:
-        file_like = BytesIO(file.read())
-        return send_file(file_like, cache_timeout=1, as_attachment=True, attachment_filename=document.name)
+    return send_file(document.as_file_like(), cache_timeout=1, as_attachment=True, attachment_filename=document.name)
 
 @app.route("/document/upload/<int:protocol_id>", methods=["POST"])
 @login_required
diff --git a/tasks.py b/tasks.py
index e82b2d4ab5b6a00b8b35d8acbda2923bafe4704d..a60fb7064c772424963ebba60f4de5acf2878f11 100644
--- a/tasks.py
+++ b/tasks.py
@@ -199,7 +199,6 @@ def parse_protocol_async(protocol_id, encoded_kwargs):
             content_private = render_template("protocol.txt", render_type=RenderType.plaintext, show_private=True, **render_kwargs)
             content_public = render_template("protocol.txt", render_type=RenderType.plaintext, show_private=False, **render_kwargs)
             if content_private != content_public:
-                print("different")
                 privacy_states.append(True)
             protocol.content_private = content_private
             protocol.content_public = content_public
@@ -316,23 +315,40 @@ def send_reminder_async(reminder_id, protocol_id):
     with app.app_context():
         reminder = MeetingReminder.query.filter_by(id=reminder_id).first()
         protocol = Protocol.query.filter_by(id=protocol_id).first()
-        reminder_text = render_template("reminder.txt", reminder=reminder, protocol=protocol)
+        reminder_text = render_template("reminder-mail.txt", reminder=reminder, protocol=protocol)
         if reminder.send_public:
             send_mail(protocol, protocol.protocoltype.public_mail, "Tagesordnung der {}".format(protocol.protocoltype.name), reminder_text)
         if reminder.send_private:
             send_mail(protocol, protocol.protocoltype.private_mail, "Tagesordnung der {}".format(protocol.protocoltype.name), reminder_text)
 
-def send_mail(protocol, to_addr, subject, content):
+def send_protocol(protocol):
+    send_protocol_async.delay(protocol.id, show_private=True)
+    send_protocol_async.delay(protocol.id, show_private=False)
+
+@celery.task
+def send_protocol_async(protocol_id, show_private):
+    with app.app_context():
+        protocol = Protocol.query.filter_by(id=protocol_id).first()
+        to_addr = protocol.protocoltype.private_mail if show_private else protocol.protocoltype.public_mail
+        subject = "{}{}-Protokoll vom {}".format("Internes " if show_private else "", protocol.protocoltype.short_name, date_filter(protocol.date))
+        mail_content = render_template("protocol-mail.txt", protocol=protocol)
+        appendix = [(document.name, document.as_file_like())
+            for document in protocol.documents
+            if show_private or not document.is_private
+        ]
+        send_mail(protocol, to_addr, subject, mail_content, appendix)
+
+
+def send_mail(protocol, to_addr, subject, content, appendix=None):
     if to_addr is not None and len(to_addr.strip()) > 0:
-        send_mail_async.delay(protocol.id, to_addr, subject, content)
+        send_mail_async.delay(protocol.id, to_addr, subject, content, appendix)
 
 @celery.task
-def send_mail_async(protocol_id, to_addr, subject, content):
+def send_mail_async(protocol_id, to_addr, subject, content, appendix):
     with app.app_context():
         protocol = Protocol.query.filter_by(id=protocol_id).first()
         try:
-            print("sending {} to {}".format(subject, to_addr))
-            mail_manager.send(to_addr, subject, content)
+            mail_manager.send(to_addr, subject, content, appendix)
         except Exception as exc:
             error = protocol.create_error("Sending Mail", "Sending mail failed", str(exc))
             db.session.add(error)
diff --git a/templates/protocol-mail.txt b/templates/protocol-mail.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9c228ea83116cdaf40ef55cf7141bf83b46432d3
--- /dev/null
+++ b/templates/protocol-mail.txt
@@ -0,0 +1,34 @@
+Protocol der {{protocol.name}} vom {{protocol.date|datify}}
+
+Datum: {{protocol.date|datify_long}}
+Zeit: von {{protocol.start_time|timify}} bis {{protocol.end_time|timify}}
+Protokollant: {{protocol.author}}
+Anwesende: {{protocol.participants}}
+
+Die Tagesordnung ist:
+{% if not protocol.has_nonplanned_tops() %}
+    {% for default_top in protocol.protocoltype.default_tops %}
+        {% if not default_top.is_at_end() %}
+* {{default_top.name}}
+        {% endif %}
+    {% endfor %}
+{% endif %}
+{% for top in protocol.tops %}
+* {{top.name }}
+{% endfor %}
+{% if not protocol.has_nonplanned_tops() %}
+    {% for default_top in protocol.protocoltype.default_tops %}
+        {% if default_top.is_at_end() %}
+* {{default_top.name}}
+        {% endif %}
+    {% endfor %}
+{% endif %}
+
+Beschlüsse:
+{% if protocol.decisions|length > 0 %}
+    {% for decision in protocol.decisions %}
+* {{decision.content}}
+    {% endfor %}
+{% else %}
+* Keine Beschlüsse
+{% endif %}
diff --git a/templates/protocol-show.html b/templates/protocol-show.html
index bc3a703dd970381d4af2cfccb69c10dfa5c3472e..af65a7b6bd238982e1c74e63571c0ef4ee06d49d 100644
--- a/templates/protocol-show.html
+++ b/templates/protocol-show.html
@@ -20,6 +20,8 @@
             {% if not protocol.is_done() %}
                 <a class="btn btn-default" href="{{url_for("get_protocol_template", protocol_id=protocol.id)}}">Vorlage</a>
                 <a class="btn btn-primary" href="{{url_for("etherpush_protocol", protocol_id=protocol.id)}}">In Etherpad</a>
+            {% else %}
+                <a class="btn btn-default" href="{{url_for("send_protocol", protocol_id=protocol.id)}}">Per Mail versenden</a>
             {% endif %}
             <a class="btn btn-default" href="{{protocol.get_etherpad_link()}}" target="_blank">Etherpad</a>
             <a class="btn btn-default" href="{{url_for("show_type", type_id=protocol.protocoltype.id)}}">Typ</a>
diff --git a/templates/reminder.txt b/templates/reminder-mail.txt
similarity index 100%
rename from templates/reminder.txt
rename to templates/reminder-mail.txt
diff --git a/utils.py b/utils.py
index cc020e5dcba17ae0cd7e80fa0c68d0351af08550..7cd92045111a0662fbe34e0ee18afcc73f686732 100644
--- a/utils.py
+++ b/utils.py
@@ -6,6 +6,7 @@ import regex
 import smtplib
 from email.mime.multipart import MIMEMultipart
 from email.mime.text import MIMEText
+from email.mime.application import MIMEApplication
 from datetime import datetime, date, timedelta
 import requests
 from io import BytesIO
@@ -68,18 +69,23 @@ class MailManager:
         self.username = getattr(config, "MAIL_USER", "")
         self.password = getattr(config, "MAIL_PASSWORD", "")
 
-    def send(self, to_addr, subject, content):
+    def send(self, to_addr, subject, content, appendix=None):
         if (not self.active
             or not self.hostname
             or not self.username
             or not self.password
             or not self.from_addr):
             return
-        msg = MIMEMultipart("alternative")
+        msg = MIMEMultipart("mixed") # todo: test if clients accept attachment-free mails set to multipart/mixed
         msg["From"] = self.from_addr
         msg["To"] = to_addr
         msg["Subject"] = subject
         msg.attach(MIMEText(content, _charset="utf-8"))
+        if appendix is not None:
+            for name, file_like in appendix:
+                part = MIMEApplication(file_like.read(), "octet-stream")
+                part["Content-Disposition"] = 'attachment; filename="{}"'.format(name)
+                msg.attach(part)
         server = smtplib.SMTP_SSL(self.hostname)
         server.login(self.username, self.password)
         server.sendmail(self.from_addr, to_addr, msg.as_string())