diff --git a/accounts/authentication.py b/accounts/authentication.py
new file mode 100644
index 0000000000000000000000000000000000000000..a274bb29ae42bdf4c8951bb5dd37b52abcbb07a5
--- /dev/null
+++ b/accounts/authentication.py
@@ -0,0 +1,23 @@
+import sys
+from accounts.models import ListUser, Token
+
+class PasswordlessAuthenticationBackend(object):
+
+    def authenticate(self, uid):
+        print('uid', uid, file=sys.stderr)
+        if not Token.objects.filter(uid=uid).exists():
+            print('no token found', file=sys.stderr)
+            return None
+        token = Token.objects.get(uid=uid)
+        print('got token', file=sys.stderr)
+        try:
+            user = ListUser.objects.get(email=token.email)
+            print('got user', file=sys.stderr)
+            return user
+        except ListUser.DoesNotExist:
+            print('new user', file=sys.stderr)
+            return ListUser.objects.create(email=token.email)
+
+
+    def get_user(self, email):
+        return ListUser.objects.get(email=email)
\ No newline at end of file
diff --git a/accounts/models.py b/accounts/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..5ce27f756a422542bf88497e2312458d187eda3b
--- /dev/null
+++ b/accounts/models.py
@@ -0,0 +1,34 @@
+from django.db import models
+from django.contrib.auth.models import (
+    AbstractBaseUser, BaseUserManager, PermissionsMixin
+)
+
+
+class Token(models.Model):
+    email = models.EmailField()
+    uid = models.CharField(max_length=255)
+
+
+class ListUser(AbstractBaseUser, PermissionsMixin):
+    email = models.EmailField(primary_key=True)
+    USERNAME_FIELD = 'email'
+    #REQUIRED_FIELDS = ['email', 'height']
+
+    objects = ListUserManager()
+
+    @property
+    def is_staff(self):
+        return self.email == 'harry.percival@example.com'
+
+    @property
+    def is_active(self):
+        return True
+
+
+class ListUserManager(BaseUserManager):
+
+    def create_user(self, email):
+        ListUser.objects.create(email=email)
+
+    def create_superuser(self, email, password):
+        self.create_user(email)
diff --git a/accounts/templates/login_email_sent.html b/accounts/templates/login_email_sent.html
new file mode 100644
index 0000000000000000000000000000000000000000..d02890e15b67d9602310a554b698e9e4aed6301a
--- /dev/null
+++ b/accounts/templates/login_email_sent.html
@@ -0,0 +1,7 @@
+<html>
+<h1>Email sent</h1>
+
+<p>Check your email, you'll find a message with a link that will log you into
+the site.</p>
+
+</html>
diff --git a/accounts/views.py b/accounts/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..a86d5a86b20b87eee3e1c2dbbde252953dfe26b1
--- /dev/null
+++ b/accounts/views.py
@@ -0,0 +1,38 @@
+import uuid
+import sys
+from django.contrib.auth import authenticate
+from django.contrib.auth import login as auth_login
+from django.core.mail import send_mail
+from django.shortcuts import redirect, render
+from django.contrib.auth import login as auth_login, logout as auth_logout
+
+from accounts.models import Token
+
+
+def login(request):
+    print('login view', file=sys.stderr)
+    uid = request.GET.get('uid')
+    user = authenticate(uid=uid)
+    if user is not None:
+        auth_login(request, user)
+    return redirect('/')
+
+
+def logout(request):
+    auth_logout(request)
+    return redirect('/')
+
+
+def send_login_email(request):
+    email = request.POST['email']
+    uid = str(uuid.uuid4())
+    Token.objects.create(email=email, uid=uid)
+    print('saving uid', uid, 'for email', email, file=sys.stderr)
+    url = request.build_absolute_uri(f'/accounts/login?uid={uid}')
+    send_mail(
+        'Your login link for Superlists',
+        f'Use this link to log in:\n\n{url}',
+        'noreply@superlists',
+        [email],
+    )
+    return render(request, 'login_email_sent.html')
\ No newline at end of file
diff --git a/superlists/settings.py b/superlists/settings.py
index a443f8d88e8f5c15918be4e15e845004d36b2f4e..aab948fab249d7436707f7d1b90e4d59c2f9ad12 100644
--- a/superlists/settings.py
+++ b/superlists/settings.py
@@ -31,13 +31,19 @@ ALLOWED_HOSTS = []
 # Application definition
 
 INSTALLED_APPS = [
-    'django.contrib.admin',
+    #'django.contrib.admin',
     'django.contrib.auth',
     'django.contrib.contenttypes',
     'django.contrib.sessions',
     'django.contrib.messages',
     'django.contrib.staticfiles',
     'lists',
+    'accounts',
+]
+
+AUTH_USER_MODEL = 'accounts.ListUser'
+AUTHENTICATION_BACKENDS = [
+    'accounts.authentication.PasswordlessAuthenticationBackend',
 ]
 
 MIDDLEWARE = [
@@ -119,3 +125,9 @@ USE_TZ = True
 # https://docs.djangoproject.com/en/2.2/howto/static-files/
 
 STATIC_URL = '/static/'
+
+EMAIL_HOST = 'smtp.gmail.com'
+EMAIL_HOST_USER = 'emil.farisan@gmail.com'
+EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_PASSWORD')
+EMAIL_PORT = 587
+EMAIL_USE_TLS = True
diff --git a/superlists/urls.py b/superlists/urls.py
index b7683ae8982769a8d10cd5dbc7fb172c819b957e..10f0e241ced16c3e23ac731cc40a705c2d33ec0d 100644
--- a/superlists/urls.py
+++ b/superlists/urls.py
@@ -1,21 +1,8 @@
-"""superlists URL Configuration
-
-The `urlpatterns` list routes URLs to views. For more information please see:
-    https://docs.djangoproject.com/en/2.2/topics/http/urls/
-Examples:
-Function views
-    1. Add an import:  from my_app import views
-    2. Add a URL to urlpatterns:  path('', views.home, name='home')
-Class-based views
-    1. Add an import:  from other_app.views import Home
-    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
-Including another URLconf
-    1. Import the include() function: from django.urls import include, path
-    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
-"""
 from django.conf.urls import url
-from lists import views
+from accounts import views
 
 urlpatterns = [
-    url(r'^$', views.home_page, name='home'),
-]
+    url(r'^send_email$', views.send_login_email, name='send_login_email'),
+    url(r'^login$', views.login, name='login'),
+    url(r'^logout$', views.logout, name='logout'),
+]
\ No newline at end of file