The Signup Endpoint That Never Sent The Confirmation Email

I could see newsletter subscriptions accumulating in the list manager as unconfirmed.

That seemed normal at first. Double opt-in begins in an unconfirmed state and becomes active after the subscriber clicks a message.

The confirmation message was never being sent.

Two Endpoints Created Similar Records

The signup path posted to Listmonk’s administrative subscriber endpoint. That interface is intended for trusted management operations. It creates or updates a subscriber silently.

The public subscription endpoint has a different contract. It initiates the public opt-in workflow and sends the confirmation message for a double-opt-in list.

Both paths can leave a row that looks like a subscriber. Only one starts the consent flow.

I had mistaken successful record creation for successful subscription.

The Database State Hid The Missing Event

Monitoring the list count would not reveal the bug. Each form submission increased the number of records. The visible state, unconfirmed, was also plausible.

The missing evidence was an end-to-end test:

  • Submit through the public form.
  • Confirm the correct list receives the request.
  • Verify that an opt-in message is sent.
  • Follow the confirmation link.
  • Confirm the member becomes active.

Without that sequence, the application was testing storage rather than user experience.

Copy Is Part Of The Protocol

The success message originally implied that signup was complete. That actively discouraged users from looking for the confirmation email.

I changed the interface to tell people to check their email and confirm. The wording now reflects the actual state transition instead of celebrating too early.

The public endpoint also uses the list’s public identifier rather than the internal numeric ID expected by administrative operations. Authentication and payload assumptions changed with the endpoint’s purpose.

A Funnel Is Only As Strong As Its Last Required Step

The signup form worked. The proxy worked. The list manager stored rows. Every component could appear healthy while no reader could actually join the list.

Subscription is not the POST request or the database insert. In a double-opt-in system, subscription is the completed consent loop.

That became the acceptance test, and it is a much better definition of success than “the endpoint returned 200.”