diff --git a/migrations/versions/188f389b2286_.py b/migrations/versions/188f389b2286_.py
new file mode 100644
index 0000000000000000000000000000000000000000..6e7f9ecd6af55e3649db8e41541ee1073a375e2c
--- /dev/null
+++ b/migrations/versions/188f389b2286_.py
@@ -0,0 +1,34 @@
+"""empty message
+
+Revision ID: 188f389b2286
+Revises: 515d261a624b
+Create Date: 2017-02-26 12:55:43.761405
+
+"""
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = '188f389b2286'
+down_revision = '515d261a624b'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+    # ### commands auto generated by Alembic - please adjust! ###
+    op.create_table('todomails',
+    sa.Column('id', sa.Integer(), nullable=False),
+    sa.Column('name', sa.String(), nullable=True),
+    sa.Column('mail', sa.String(), nullable=True),
+    sa.PrimaryKeyConstraint('id'),
+    sa.UniqueConstraint('name')
+    )
+    # ### end Alembic commands ###
+
+
+def downgrade():
+    # ### commands auto generated by Alembic - please adjust! ###
+    op.drop_table('todomails')
+    # ### end Alembic commands ###
diff --git a/models/database.py b/models/database.py
index f2664d3075e28ca1938a743128c3b23206aa1c23..e91c3f4531e35a05909654f60e9ff4f34d794d21 100644
--- a/models/database.py
+++ b/models/database.py
@@ -5,7 +5,7 @@ import math
 from io import StringIO, BytesIO
 
 from shared import db
-from utils import random_string, url_manager, get_etherpad_url
+from utils import random_string, url_manager, get_etherpad_url, split_terms
 from models.errors import DateNotMatchingException
 
 import os
@@ -326,6 +326,12 @@ class Todo(db.Model):
             return None
         return candidates[0]
 
+    def get_users(self):
+        return [
+            user.lower().strip()
+            for user in split_terms(self.who, separators=" ,\t")
+        ]
+
     def get_state(self):
         return "[Erledigt]" if self.done else "[Offen]"
     def get_state_plain(self):
@@ -428,3 +434,20 @@ class Error(db.Model):
         if len(lines) <= 4:
             return "\n".join(lines)
         return "\n".join(lines[:2], "…", lines[-2:])
+
+class TodoMail(db.Model):
+    __tablename__ = "todomails"
+    id = db.Column(db.Integer, primary_key=True)
+    name = db.Column(db.String, unique=True)
+    mail = db.Column(db.String)
+
+    def __init__(self, name, mail):
+        self.name = name
+        self.mail = mail
+    
+    def __repr__(self):
+        return "<TodoMail(name='{}', mail='{}')>".format(
+            self.name, self.mail)
+
+    def get_formatted_mail(self):
+        return "{} <{}>".format(self.name, self.mail)
diff --git a/server.py b/server.py
index b778c3da577edb07922db662586eaf9d75cb2ae0..798fc9e80a18fda8117e16fea87a825d3b2b7d48 100755
--- a/server.py
+++ b/server.py
@@ -21,9 +21,9 @@ import math
 import config
 from shared import db, date_filter, datetime_filter, date_filter_long, time_filter, ldap_manager, security_manager, current_user, check_login, login_required, group_required, class_filter
 from utils import is_past, mail_manager, url_manager, get_first_unused_int, set_etherpad_text, get_etherpad_text, split_terms, optional_int_arg
-from models.database import ProtocolType, Protocol, DefaultTOP, TOP, Document, Todo, Decision, MeetingReminder, Error
-from views.forms import LoginForm, ProtocolTypeForm, DefaultTopForm, MeetingReminderForm, NewProtocolForm, DocumentUploadForm, KnownProtocolSourceUploadForm, NewProtocolSourceUploadForm, ProtocolForm, TopForm, SearchForm, NewProtocolFileUploadForm, NewTodoForm, TodoForm
-from views.tables import ProtocolsTable, ProtocolTypesTable, ProtocolTypeTable, DefaultTOPsTable, MeetingRemindersTable, ErrorsTable, TodosTable, DocumentsTable, DecisionsTable, TodoTable, ErrorTable
+from models.database import ProtocolType, Protocol, DefaultTOP, TOP, Document, Todo, Decision, MeetingReminder, Error, TodoMail
+from views.forms import LoginForm, ProtocolTypeForm, DefaultTopForm, MeetingReminderForm, NewProtocolForm, DocumentUploadForm, KnownProtocolSourceUploadForm, NewProtocolSourceUploadForm, ProtocolForm, TopForm, SearchForm, NewProtocolFileUploadForm, NewTodoForm, TodoForm, TodoMailForm
+from views.tables import ProtocolsTable, ProtocolTypesTable, ProtocolTypeTable, DefaultTOPsTable, MeetingRemindersTable, ErrorsTable, TodosTable, DocumentsTable, DecisionsTable, TodoTable, ErrorTable, TodoMailsTable
 
 app = Flask(__name__)
 app.config.from_object(config)
@@ -977,6 +977,53 @@ def delete_error(error_id):
     db.session.commit()
     flash("Fehler {} gelöscht.".format(name), "alert-success")
     return redirect(request.args.get("next") or url_for("list_errors"))
+
+@app.route("/todomails/list")
+@login_required
+def list_todomails():
+    todomails = TodoMail.query.all()
+    todomails_table = TodoMailsTable(todomails)
+    return render_template("todomails-list.html", todomails=todomails, todomails_table=todomails_table)
+
+@app.route("/todomail/new", methods=["GET", "POST"])
+@login_required
+def new_todomail():
+    form = TodoMailForm()
+    if form.validate_on_submit():
+        todomail = TodoMail(form.name.data, form.mail.data)
+        db.session.add(todomail)
+        db.session.commit()
+        flash("Die Todomailzuordnung für {} wurde angelegt.".format(todomail.name), "alert-success")
+        return redirect(request.args.get("next") or url_for("list_todomails"))
+    return render_template("todomail-new.html", form=form)
+
+@app.route("/todomail/edit/<int:todomail_id>", methods=["GET", "POST"])
+@login_required
+def edit_todomail(todomail_id):
+    todomail = TodoMail.query.filter_by(id=todomail_id).first()
+    if todomail is None:
+        flash("Invalide Todo-Mail-Zuordnung.", "alert-error")
+        return redirect(request.args.get("next") or url_for("list_todomails"))
+    form = TodoMailForm(obj=todomail)
+    if form.validate_on_submit():
+        form.populate_obj(todomail)
+        db.session.commit()
+        flash("Die Todo-Mail-Zuordnung wurde geändert.", "alert-success")
+        return redirect(request.args.get("next") or url_for("list_todomails"))
+    return render_template("todomail-edit.html", todomail=todomail, form=form)
+
+@app.route("/todomail/delete/<int:todomail_id>")
+@login_required
+def delete_todomail(todomail_id):
+    todomail = TodoMail.query.filter_by(id=todomail_id).first()
+    if todomail is None:
+        flash("Invalide Todomailzuordnung.", "alert-error")
+        return redirect(request.args.get("next") or url_for("list_todomails"))
+    name = todomail.name
+    db.session.delete(todomail)
+    db.session.commit()
+    flash("Die Todo-Mail-Zuordnung für {} wurde gelöscht.".format(name), "alert-success")
+    return redirect(request.args.get("next") or url_for("list_todomails"))
     
 
 @app.route("/login", methods=["GET", "POST"])
diff --git a/tasks.py b/tasks.py
index a60fb7064c772424963ebba60f4de5acf2878f11..5ea7a53cb7adf66e9a084e857b6e727c87431f30 100644
--- a/tasks.py
+++ b/tasks.py
@@ -5,7 +5,7 @@ import subprocess
 import shutil
 import tempfile
 
-from models.database import Document, Protocol, Error, Todo, Decision, TOP, DefaultTOP, MeetingReminder
+from models.database import Document, Protocol, Error, Todo, Decision, TOP, DefaultTOP, MeetingReminder, TodoMail
 from models.errors import DateNotMatchingException
 from server import celery, app
 from shared import db, escape_tex, unhyphen, date_filter, datetime_filter, date_filter_long, date_filter_short, time_filter, class_filter
@@ -324,6 +324,7 @@ def send_reminder_async(reminder_id, protocol_id):
 def send_protocol(protocol):
     send_protocol_async.delay(protocol.id, show_private=True)
     send_protocol_async.delay(protocol.id, show_private=False)
+    send_todomails_async.delay(protocol.id)
 
 @celery.task
 def send_protocol_async(protocol_id, show_private):
@@ -338,6 +339,27 @@ def send_protocol_async(protocol_id, show_private):
         ]
         send_mail(protocol, to_addr, subject, mail_content, appendix)
 
+@celery.task
+def send_todomails_async(protocol_id):
+    with app.app_context():
+        protocol = Protocol.query.filter_by(id=protocol_id).first()
+        all_todos = Todo.query.filter(Todo.done == False).all()
+        users = {user for todo in all_todos for user in todo.get_users()}
+        grouped_todos = {
+            user: [todo for todo in all_todos if user in todo.get_users()]
+            for user in users
+        }
+        subject = "Du hast noch was zu tun!"
+        for user in users:
+            todomail = TodoMail.query.filter(TodoMail.name.ilike(user)).first()
+            if todomail is None:
+                error = protocol.create_error("Sending Todomail", "Sending Todomail failed.", "User {} has no Todo-Mail-Assignment.".format(user))
+                db.session.add(error)
+                db.session.commit()
+                continue
+            to_addr = todomail.get_formatted_mail()
+            mail_content = render_template("todo-mail.txt", protocol=protocol, todomail=todomail, todos=grouped_todos[user])
+            send_mail(protocol, to_addr, subject, mail_content)
 
 def send_mail(protocol, to_addr, subject, content, appendix=None):
     if to_addr is not None and len(to_addr.strip()) > 0:
diff --git a/templates/layout.html b/templates/layout.html
index e141b04743902e49572b8cff975b732249c4a338..c8b88d049f7db0837159b8bad6474e589a56dd36 100644
--- a/templates/layout.html
+++ b/templates/layout.html
@@ -27,7 +27,7 @@
         <div id="navbar" class="navbar-collapse collapse">
             <ul class="nav navbar-nav">
                 {% if check_login() %}
-                <li><a href="{{url_for("new_protocol")}}">Neues Protokoll</a></li>
+                <li><a href="{{url_for("new_protocol")}}">Neu</a></li>
                 {% endif %}
                 <li><a href="{{url_for("list_protocols")}}">Protokolle</a></li>
                 {% if check_login() %}
@@ -37,6 +37,7 @@
                 {% if check_login() %}
                 <li><a href="{{url_for("list_types")}}">Typen</a></li>
                 <li><a href="{{url_for("list_errors")}}">Fehler</a></li>
+                <li><a href="{{url_for("list_todomails")}}">Todo Mails</a></li>
                 {% endif %}
                 {# todo: add more links #}
             </ul>
diff --git a/templates/todo-mail.txt b/templates/todo-mail.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a377bf60f971c9056776c06768a94f47f8fb013b
--- /dev/null
+++ b/templates/todo-mail.txt
@@ -0,0 +1,13 @@
+Hallo {{todomail.name}},
+
+Du hast für "{{protocol.protocoltype.name}}" noch offene Todos:
+
+{% for todo in todos %}
+{{todo.who}}:
+    {{todo.description}}
+{% endfor %}
+
+Fühle die hiermit daran erinnert!
+
+Viele Grüße,
+Dein Protokollsystem
diff --git a/templates/todomail-edit.html b/templates/todomail-edit.html
new file mode 100644
index 0000000000000000000000000000000000000000..6845b49f4c657f24fcb81012f2c348a175a5ef6a
--- /dev/null
+++ b/templates/todomail-edit.html
@@ -0,0 +1,9 @@
+{% extends "layout.html" %}
+{% from "macros.html" import render_form %}
+{% block title %}Todomail ändern{% endblock %}
+
+{% block content %}
+<div class="container">
+    {{render_form(form, action_url=url_for("edit_todomail", todomail_id=todomail.id), action_text="Ändern")}}
+</div>
+{% endblock %}
diff --git a/templates/todomail-new.html b/templates/todomail-new.html
new file mode 100644
index 0000000000000000000000000000000000000000..a34e1f7dcefd8bd79ccb4affa756591113851ce2
--- /dev/null
+++ b/templates/todomail-new.html
@@ -0,0 +1,9 @@
+{% extends "layout.html" %}
+{% from "macros.html" import render_form %}
+{% block title %}Neue Todomail{% endblock %}
+
+{% block content %}
+<div class="container">
+    {{render_form(form, action_url=url_for("new_todomail"), action_text="Ändern")}}
+</div>
+{% endblock %}
diff --git a/templates/todomails-list.html b/templates/todomails-list.html
new file mode 100644
index 0000000000000000000000000000000000000000..727615caa8a139ecca0b5a43ff7c2c6e5e54bcb8
--- /dev/null
+++ b/templates/todomails-list.html
@@ -0,0 +1,9 @@
+{% extends "layout.html" %}
+{% from "macros.html" import render_table %}
+{% block title %}Todomails{% endblock %}
+
+{% block content %}
+<div class="container">
+    {{render_table(todomails_table)}}
+</div>
+{% endblock %}
diff --git a/utils.py b/utils.py
index d98df8186029fcac15db567db3e92862d0498762..efe13167bdf6078c8a3adb2eef31c5a3e9b1118c 100644
--- a/utils.py
+++ b/utils.py
@@ -75,6 +75,7 @@ class MailManager:
             or not self.username
             or not self.password
             or not self.from_addr):
+            print("Not sending mail {} to {}".format(subject, to_addr))
             return
         msg = MIMEMultipart("mixed") # todo: test if clients accept attachment-free mails set to multipart/mixed
         msg["From"] = self.from_addr
diff --git a/views/forms.py b/views/forms.py
index 9a5bb77b311c4f4d22043aebf9721e9e0a837f09..6e91d33d24760646ee744e435dec6081cf860373 100644
--- a/views/forms.py
+++ b/views/forms.py
@@ -108,3 +108,7 @@ class TodoForm(FlaskForm):
     description = StringField("Aufgabe", validators=[InputRequired("Bitte gib an, was erledigt werden soll.")])
     tags = StringField("Weitere Tags")
     done = BooleanField("Erledigt")
+
+class TodoMailForm(FlaskForm):
+    name = StringField("Name", validators=[InputRequired("Du musst den Namen angeben, der zugeordnet werden soll.")])
+    mail = StringField("Mail", validators=[InputRequired("Du musst die Mailadresse angeben, die zugeordnet werden soll.")])
diff --git a/views/tables.py b/views/tables.py
index 2c09ec9ca3494f51ee7675be564fbe3e61c35bfb..f7ab1f9ae83e572e04f471b4511cb38bb5875bda 100644
--- a/views/tables.py
+++ b/views/tables.py
@@ -314,3 +314,21 @@ class DocumentsTable(Table):
                 if document.protocol.protocoltype.has_modify_right(user)
                 else ""
         ]
+
+class TodoMailsTable(Table):
+    def __init__(self, todomails):
+        super().__init__("Todo-Mail-Zuordnungen", todomails, url_for("new_todomail"))
+
+    def headers(self):
+        return ["Name", "Mail", ""]
+
+    def row(self, todomail):
+        return [
+            todomail.name,
+            todomail.mail,
+            Table.concat([
+                Table.link(url_for("edit_todomail", todomail_id=todomail.id), "Ändern"),
+                Table.link(url_for("delete_todomail", todomail_id=todomail.id), "Löschen", confirm="Bist du dir sicher, dass du die Todomailzuordnung {} zu {} löschen willst?".format(todomail.name, todomail.mail))
+            ])
+        ]
+