From 9495daa70174757bc32c40bdd5d7a7f32f1091ba Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Mon, 26 Oct 2026 16:42:10 +0000 Subject: [PATCH] =?UTF-8?q?newsletter:=20the=20unsubscribe=20PUT=20needs?= =?UTF-8?q?=20the=20email=20field=20=E2=80=94=20it=20was=20a=20silent=2040?= =?UTF-8?q?0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The end-to-end probe against the live listmonk caught this: PUT /api/subscribers/{id} with {"lists": []} returns 400 {"message":"Invalid email."}, leaving the subscriber on the list. It needs {"email": ..., "lists": []}. The failed request was only a log warning, so the reconcile's main job — taking lapsed members off the Members list — has never worked; only the DELETE branch did anything, which is the branch this series just removed. Now both classes unsubscribe successfully and keep their record. --- app/main.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/main.py b/app/main.py index 9adb527..6bb6b3b 100644 --- a/app/main.py +++ b/app/main.py @@ -482,10 +482,13 @@ async def listmonk_reconcile() -> dict: # Both classes leave the list the same way: unsubscribe, keep the # record. Nothing is deleted. reason = "inactive member" if email in member_emails else "not a member" + # listmonk validates the PUT body's email field: omitting it is a + # 400 "Invalid email." and the subscriber stays on the list (which + # is why the inactive-member branch never actually worked). r = await client.put( f"{LISTMONK_BASE}/api/subscribers/{sid}", headers=auth, - json={"lists": []}, + json={"email": s.get("email"), "lists": []}, ) if r.status_code in (200, 201): removed += 1