diff --git a/app/templates/auth/email/confirm.html.j2 b/app/templates/auth/email/confirm.html.j2
new file mode 100644
index 0000000000000000000000000000000000000000..599c4787ceb4c7f5b1e29a5f2a6bfc9992e4d215
--- /dev/null
+++ b/app/templates/auth/email/confirm.html.j2
@@ -0,0 +1,8 @@
+<p>Dear {{ user.username }},</p>
+<p>Welcome to <b>Opaque</b>!</p>
+<p>To confirm your account please <a href="{{ url_for('auth.confirm', 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.confirm', token=token, _external=True) }}</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/confirm.txt.j2 b/app/templates/auth/email/confirm.txt.j2
new file mode 100644
index 0000000000000000000000000000000000000000..5ba0670b9a2c596d5120f3faf3b03ddb1216557f
--- /dev/null
+++ b/app/templates/auth/email/confirm.txt.j2
@@ -0,0 +1,11 @@
+Dear {{ user.username }},
+
+Welcome to Opaque!
+
+To confirm your account please click on the following link:
+{{ url_for('auth.confirm', token=token, _external=True) }}
+
+Sincerely,
+The Opaque Team
+
+Note: replies to this email address are not monitored.
diff --git a/tests/test_user_model.py b/tests/test_user_model.py
index 3c794b0bb1174d91850b88738ec9b162e4891ba6..b7d08147443a1b793387787163dd0c3ddd86671f 100644
--- a/tests/test_user_model.py
+++ b/tests/test_user_model.py
@@ -1,5 +1,7 @@
 import unittest
+import time
 from app.models import User
+from app import db
 
 
 class UserModelTestCase(unittest.TestCase):
@@ -21,3 +23,27 @@ class UserModelTestCase(unittest.TestCase):
         u = User(password='cat')
         u2 = User(password='cat')
         self.assertTrue(u.password_hash != u2.password_hash)
+
+    def test_valid_confirmation_token(self):
+        u = User(password='cat')
+        db.session.add(u)
+        db.session.commit()
+        token = u.generate_confirmation_token()
+        self.assertTrue(u.confirm(token))
+
+    def test_invalid_confirmation_token(self):
+        u1 = User(password='cat')
+        u2 = User(password='dog')
+        db.session.add(u1)
+        db.session.add(u2)
+        db.session.commit()
+        token = u1.generate_confirmation_token()
+        self.assertFalse(u2.confirm(token))
+
+    def test_expired_confirmation_token(self):
+        u = User(password='cat')
+        db.session.add(u)
+        db.session.commit()
+        token = u.generate_confirmation_token(1)
+        time.sleep(2)
+        self.assertFalse(u.confirm(token))