import logging from django.forms import ModelForm from django.views.decorators.csrf import csrf_exempt from django.shortcuts import render from .models import Unsubscription logger = logging.getLogger(__name__) class UnsubscribeForm(ModelForm): class Meta: model = Unsubscription fields = ['email', 'mailout'] @csrf_exempt # Submitted directly by Gmail and similar - no CSRF token. 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: List-Unsubscribe-Post: List-Unsubscribe=One-Click Interfaces like Gmail will then provide a user interface to unsubscribe which will hit this endpoint. Our understanding is that Gmail will submit the form with and HTTP POST request, but with GET-style URL parameters. Hence this feature has been built to work both with GET and POST-style data as well as GET and POST methods, just in case. Test it like this: curl -X POST -d 'email=foo@bar.com&mailout=jan2024-new' https://sfconservancy.org/contacts/unsubscribe/ curl -X POST 'https://sfconservancy.org/contacts/unsubscribe/?email=foo@bar.com&mailout=jan2024-new' Or visit in a browser: https://sfconservancy.org/contacts/unsubscribe/?email=foo@bar.com&mailout=jan2024-new """ if request.method == 'POST': logger.debug('Unsubscribe GET: %s', request.GET) logger.debug('Unsubscribe POST: %s', request.POST) form = UnsubscribeForm(request.GET.dict() | request.POST.dict()) if form.is_valid(): form.save() logger.info('Unsubscribed %s', form.cleaned_data['email']) return render(request, 'contacts/unsubscribe_success.html') else: form = UnsubscribeForm(request.GET.dict() | request.POST.dict()) return render(request, 'contacts/unsubscribe.html', {'form': form})