diff --git a/.flaskenv b/.flaskenv
index f88b6e5b9015d74cef7f8cb429bbf93297cb1d75..0a7611db03c62e8a30c90a199104a8420d0bed3f 100644
--- a/.flaskenv
+++ b/.flaskenv
@@ -1,2 +1,4 @@
 FLASK_APP=opaque.py
 FLASK_ENV=development
+OPAQUE_MAIL_SUBJECT_PREFIX=[Opaque]
+OPAQUE_MAIL_SENDER=Opaque Admin <inf_sfb1288@uni-bielefeld.de>
diff --git a/app/__init__.py b/app/__init__.py
index f77d7e2273600493690264b85209204c7861b5bc..7080fdbcb5dca8c04748f8e176608a76c750b11b 100644
--- a/app/__init__.py
+++ b/app/__init__.py
@@ -1,10 +1,12 @@
 from config import config
 from flask import Flask
 from flask_login import LoginManager
+from flask_mail import Mail
 from flask_sqlalchemy import SQLAlchemy
 
 
 db = SQLAlchemy()
+mail = Mail()
 
 login_manager = LoginManager()
 login_manager.login_view = 'auth.login'
@@ -17,6 +19,7 @@ def create_app(config_name):
 
     db.init_app(app)
     login_manager.init_app(app)
+    mail.init_app(app)
 
     from .auth import auth as auth_blueprint
     app.register_blueprint(auth_blueprint, url_prefix='/auth')
diff --git a/app/auth/forms.py b/app/auth/forms.py
index 77b25333c3e3f7417ff5a40811804b0a3ef2d7f1..43a64679f60c1250d310e0435b7a53008e896d2b 100644
--- a/app/auth/forms.py
+++ b/app/auth/forms.py
@@ -15,3 +15,9 @@ class LoginForm(FlaskForm):
 
 class RegistrationForm(FlaskForm):
     email = StringField('Email', validators=[DataRequired(), Length(1, 64), Email()])
+
+
+class PasswordResetRequestForm(FlaskForm):
+    email = StringField('Email', validators=[DataRequired(), Length(1, 64),
+                                             Email()])
+    submit = SubmitField('Reset Password')
diff --git a/app/auth/views.py b/app/auth/views.py
index 5eef58684945e518b8633388c73f8e968370fde1..b2e6ba68bd701f264d5bd000a425dd6821b8f315 100644
--- a/app/auth/views.py
+++ b/app/auth/views.py
@@ -1,7 +1,8 @@
 from flask import flash, redirect, render_template, request, url_for
 from flask_login import login_required, login_user, logout_user
 from . import auth
-from .forms import LoginForm
+from .forms import LoginForm, PasswordResetRequestForm
+from ..email import send_email
 from ..models import User
 
 
@@ -31,3 +32,18 @@ def logout():
 @auth.route('/register', methods=['GET', 'POST'])
 def register():
     return render_template('auth/register.html.j2')
+
+
+@auth.route('/reset', methods=['GET', 'POST'])
+def password_reset_request():
+    form = PasswordResetRequestForm()
+    if form.validate_on_submit():
+        user = User.query.filter_by(email=form.email.data.lower()).first()
+        if user:
+            token = user.generate_reset_token()
+            send_email(user.email, 'Reset Your Password',
+                       'auth/email/reset_password',
+                       user=user, token=token)
+        flash('An email with instructions to reset your password has been '
+              'sent to you.')
+        return redirect(url_for('auth.login'))
diff --git a/app/templates/auth/email/reset_password.html b/app/templates/auth/email/reset_password.html
new file mode 100644
index 0000000000000000000000000000000000000000..5b58a2207f8b2368ccc70a975745a71c8e5d6ebe
--- /dev/null
+++ b/app/templates/auth/email/reset_password.html
@@ -0,0 +1,8 @@
+<p>Dear {{ user.username }},</p>
+<p>To reset your password <a href="{{ url_for('auth.password_reset', token=token, _external=True) }}">click here</a>.</p>
+<p>Alternatively, you can paste the following link in your browser's address bar:</p>
+<p>{{ url_for('auth.password_reset', token=token, _external=True) }}</p>
+<p>If you have not requested a password reset simply ignore this message.</p>
+<p>Sincerely,</p>
+<p>The Opaque Team</p>
+<p><small>Note: replies to this email address are not monitored.</small></p>
diff --git a/app/templates/auth/email/reset_password.txt b/app/templates/auth/email/reset_password.txt
new file mode 100644
index 0000000000000000000000000000000000000000..cecc5a2448973081a83f00ec0d8fab46338789a0
--- /dev/null
+++ b/app/templates/auth/email/reset_password.txt
@@ -0,0 +1,13 @@
+Dear {{ user.username }},
+
+To reset your password click on the following link:
+
+{{ url_for('auth.password_reset', token=token, _external=True) }}
+
+If you have not requested a password reset simply ignore this message.
+
+Sincerely,
+
+The Opaque Team
+
+Note: replies to this email address are not monitored.
diff --git a/requirements.txt b/requirements.txt
index 5e13218c5d67c835b4a2b2ac4af8e2c764852d23..a4367aa7e1181e148e02d01b9722d757c3cd3598 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,6 @@
 Flask==1.0.3
 Flask-Login==0.4.1
+Flask-Mail==0.9.1
 Flask-Migrate==2.5.2
 Flask-SQLAlchemy==2.4.0
 Flask-WTF==0.14.2