diff --git a/conservancy/contacts/admin.py b/conservancy/contacts/admin.py
index 94048d4b..f6c68b1c 100644
--- a/conservancy/contacts/admin.py
+++ b/conservancy/contacts/admin.py
@@ -1,10 +1,8 @@
 from django.contrib import admin
 
-from .models import ContactEntry
-
-
-@admin.register(ContactEntry)
-class ContactEntryAdmin(admin.ModelAdmin):
-    list_display = ('email', 'subscribe_conservancy')
+from .models import Unsubscription
 
 
+@admin.register(Unsubscription)
+class UnsubscriptionAdmin(admin.ModelAdmin):
+    list_display = ['created', 'email']
diff --git a/conservancy/contacts/migrations/0001_initial.py b/conservancy/contacts/migrations/0001_initial.py
new file mode 100644
index 00000000..e10b2fab
--- /dev/null
+++ b/conservancy/contacts/migrations/0001_initial.py
@@ -0,0 +1,32 @@
+# Generated by Django 4.2.11 on 2024-04-09 08:01
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = []
+
+    operations = [
+        migrations.CreateModel(
+            name='Unsubscription',
+            fields=[
+                (
+                    'id',
+                    models.AutoField(
+                        auto_created=True,
+                        primary_key=True,
+                        serialize=False,
+                        verbose_name='ID',
+                    ),
+                ),
+                ('created', models.DateTimeField(auto_now_add=True)),
+                ('email', models.EmailField(max_length=254)),
+            ],
+            options={
+                'ordering': ['created'],
+            },
+        ),
+    ]
diff --git a/conservancy/contacts/migrations/__init__.py b/conservancy/contacts/migrations/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/conservancy/contacts/models.py b/conservancy/contacts/models.py
index 14ac7484..58e89a75 100644
--- a/conservancy/contacts/models.py
+++ b/conservancy/contacts/models.py
@@ -1,14 +1,9 @@
 from django.db import models
 
 
-class ContactEntry(models.Model):
-    """Conservancy contact system
-
-    Hopefully this will be deprecated soon"""
-
-    email = models.EmailField() # should make it unique, but we really cannot
-    subscribe_conservancy = models.BooleanField(default=False)
+class Unsubscription(models.Model):
+    created = models.DateTimeField(auto_now_add=True, blank=True)
+    email = models.EmailField()
 
     class Meta:
-        ordering = ('email',)
-
+        ordering = ['created']
diff --git a/conservancy/contacts/templates/contacts/unsubscribe.html b/conservancy/contacts/templates/contacts/unsubscribe.html
new file mode 100644
index 00000000..86de5a67
--- /dev/null
+++ b/conservancy/contacts/templates/contacts/unsubscribe.html
@@ -0,0 +1,10 @@
+{% extends "base_conservancy.html" %}
+{% block outercontent %}
+  <div class="mw8 center ph2 ph3 mb4">
+    <h1>Unsubscribe</h1>
+    <form action="." method="post">
+      {{ form.as_p }}
+      <p><button type="submit" class="ph3 pv2">Submit</button></p>
+    </form>
+  </div>
+{% endblock %}
diff --git a/conservancy/contacts/templates/contacts/unsubscribe_success.html b/conservancy/contacts/templates/contacts/unsubscribe_success.html
new file mode 100644
index 00000000..e4938995
--- /dev/null
+++ b/conservancy/contacts/templates/contacts/unsubscribe_success.html
@@ -0,0 +1,6 @@
+{% extends "base_conservancy.html" %}
+{% block outercontent %}
+  <div class="mw8 center ph2 ph3 mb4">
+    <h1>Unsubscribe successful</h1>
+  </div>
+{% endblock %}
diff --git a/conservancy/contacts/urls.py b/conservancy/contacts/urls.py
index 661e6891..74f1c84d 100644
--- a/conservancy/contacts/urls.py
+++ b/conservancy/contacts/urls.py
@@ -1,7 +1,7 @@
 from django.urls import path
 
-from .views import subscribe
+from .views import unsubscribe
 
 urlpatterns = [
-    path('', subscribe),
+    path('unsubscribe/', unsubscribe),
 ]
diff --git a/conservancy/contacts/views.py b/conservancy/contacts/views.py
index 95ccfc09..65ea3445 100644
--- a/conservancy/contacts/views.py
+++ b/conservancy/contacts/views.py
@@ -1,25 +1,31 @@
+import logging
+
 from django.forms import ModelForm
+from django.views.decorators.csrf import csrf_exempt
 from django.shortcuts import render
 
-from .models import ContactEntry
+from .models import Unsubscription
+
+logger = logging.getLogger(__name__)
+
+class UnsubscribeForm(ModelForm):
+    class Meta:
+        model = Unsubscription
+        fields = ['email']
 
 
-def subscribe(request):
-    """Mailing list subscription form
-    """
-
-    class ContactEntryForm(ModelForm):
-        class Meta:
-            model = ContactEntry
-
-    ContactEntryForm.base_fields['subscribe_conservancy'].label = 'Receive Software Freedom Conservancy updates'
-
+# Exempt from CSRF protection so that it can be triggered by Gmail's on-click
+# unsubscribe.
+@csrf_exempt
+def unsubscribe(request):
     if request.method == 'POST':
-        form = ContactEntryForm(request.POST)
+        logger.debug('Unsubscribe GET: %s', request.GET)
+        logger.debug('Unsubscribe POST: %s', request.POST)
+        form = UnsubscribeForm(request.POST)
         if form.is_valid():
             form.save()
-            return render(request, 'contacts/subscribe_success.html', {'form': form.cleaned_data})
+            logger.info('Unsubscribed %s', form.cleaned_data['email'])
+            return render(request, 'contacts/unsubscribe_success.html')
     else:
-        form = ContactEntryForm()
-
-    return render(request, 'contacts/subscribe.html', {'form': form})
+        form = UnsubscribeForm()
+    return render(request, 'contacts/unsubscribe.html', {'form': form})
diff --git a/conservancy/settings/base.py b/conservancy/settings/base.py
index 1d5c3132..6ca284d6 100644
--- a/conservancy/settings/base.py
+++ b/conservancy/settings/base.py
@@ -59,6 +59,11 @@ LOGGING = {
             'handlers': ['console'],
             'propagate': False,
         },
+        'conservancy.contacts': {
+            'handlers': ['console'],
+            'level': 'DEBUG',
+            'propagate': False,
+        }
     },
     'root': {
         'handlers': ['console'],
diff --git a/conservancy/urls.py b/conservancy/urls.py
index a23c6baa..dc2fe862 100644
--- a/conservancy/urls.py
+++ b/conservancy/urls.py
@@ -30,6 +30,7 @@ urlpatterns = [
     path('assignment/', include('conservancy.assignment.urls')),
     path('blog/', include('conservancy.blog.urls')),
     path('casts/the-corresponding-source/', include('conservancy.podjango.urls')),
+    path('contacts/', include('conservancy.contacts.urls')),
     path('contractpatch/', include('conservancy.contractpatch.urls')),
     path('feeds/', feeds.view),
     path('feeds/blog/', feeds.BlogFeed()),