feat(notifications): per-recipient mute endpoint + List-Unsubscribe header on approval emails · Issue #297 · LeanerCloud/cloud-commitments-cli · GitHub
Skip to content

feat(notifications): per-recipient mute endpoint + List-Unsubscribe header on approval emails #297

Closed

Description

@cristim

Background

#287 (styled email approve/cancel buttons + summary block) called for a List-Unsubscribe header on outgoing approval emails so a recipient added to a notification list they didn't ask for can self-serve out. The header requires a per-recipient mute endpoint backend, which doesn't exist today — so #287 deferred this and shipped without the header.

This issue tracks adding the endpoint + the header.

What needs to happen

  1. Per-recipient mute endpoint: GET /api/notifications/unsubscribe?token=<signed-recipient-token> (token-only, AuthPublic like the approve/cancel routes). Idempotent. Returns a small confirmation page. The token signs the (recipient_email, scope) tuple so a stray subscriber can opt out of "purchase approvals" without losing other notifications.
  2. muted_recipients table (or column on a per-recipient settings table — confirm the existing notifications schema):
    • recipient_email (text)
    • scope (enum: purchase_approvals / ri_exchange_approvals / etc.)
    • muted_at
  3. Email send path consults the mute table before adding a recipient to To/Cc.
  4. List-Unsubscribe header on outgoing emails:
    List-Unsubscribe: <https://.../api/notifications/unsubscribe?token=...>, <mailto:unsubscribe@...?subject=Unsubscribe>
    List-Unsubscribe-Post: List-Unsubscribe=One-Click
    
    The One-Click variant is what Gmail / Outlook surface as the "Unsubscribe" affordance in the message header.
  5. Test: subscribe email → mute via the endpoint → next send to that recipient skips them in To/Cc.

Acceptance

  • A recipient can click the List-Unsubscribe header link or affordance and stop receiving the targeted notification scope.
  • The mute is per-scope: opting out of purchase-approval emails does NOT mute RI-exchange emails (or whatever scopes exist).
  • The send path filters the recipient list at send time, not at template-render time.

References

Activity

  1. 8 remaining items

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions