contacts: Add field to represent the mailout the unsubscribe came from

This commit is contained in:
Ben Sturmfels 2024-04-10 16:18:51 +10:00
parent 9c01770b3c
commit 495f841d39
Signed by: bsturmfels
GPG key ID: 023C05E2C9C068F0
4 changed files with 37 additions and 6 deletions

View file

@ -5,4 +5,5 @@ from .models import Unsubscription
@admin.register(Unsubscription) @admin.register(Unsubscription)
class UnsubscriptionAdmin(admin.ModelAdmin): class UnsubscriptionAdmin(admin.ModelAdmin):
list_display = ['created', 'email'] list_display = ['created', 'email', 'mailout']
search_fields = ['email', 'mailout']

View file

@ -0,0 +1,19 @@
# Generated by Django 4.2.11 on 2024-04-10 02:02
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('contacts', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='unsubscription',
name='mailout',
field=models.SlugField(default=''),
preserve_default=False,
),
]

View file

@ -4,6 +4,7 @@ from django.db import models
class Unsubscription(models.Model): class Unsubscription(models.Model):
created = models.DateTimeField(auto_now_add=True, blank=True) created = models.DateTimeField(auto_now_add=True, blank=True)
email = models.EmailField() email = models.EmailField()
mailout = models.SlugField()
class Meta: class Meta:
ordering = ['created'] ordering = ['created']

View file

@ -11,17 +11,27 @@ logger = logging.getLogger(__name__)
class UnsubscribeForm(ModelForm): class UnsubscribeForm(ModelForm):
class Meta: class Meta:
model = Unsubscription model = Unsubscription
fields = ['email'] fields = ['email', 'mailout']
# Exempt from CSRF protection so that it can be triggered by Gmail's on-click @csrf_exempt # Submitted directly by Gmail and similar - no CSRF token.
# unsubscribe.
@csrf_exempt
def unsubscribe(request): def unsubscribe(request):
"""Endpoint for use with Gmail one-click unsubscribe or similar.
Gmail now requires "List-Unsubscribe" headers for senders over a certain
monthly volume (currently 5000 emails). Add the following headers to your
mailout:
List-Unsubscribe: <https://sfconservancy.org/contacts/unsubscribe/?email=foo@bar.com&mailout=jan2024-news>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
Interfaces like Gmail will then provide a user interface to unsubscribe
which will hit this endpoint.
"""
if request.method == 'POST': if request.method == 'POST':
logger.debug('Unsubscribe GET: %s', request.GET) logger.debug('Unsubscribe GET: %s', request.GET)
logger.debug('Unsubscribe POST: %s', request.POST) logger.debug('Unsubscribe POST: %s', request.POST)
form = UnsubscribeForm(request.GET | request.POST) form = UnsubscribeForm(request.GET)
if form.is_valid(): if form.is_valid():
form.save() form.save()
logger.info('Unsubscribed %s', form.cleaned_data['email']) logger.info('Unsubscribed %s', form.cleaned_data['email'])