Skip to main content

listSubscribe

The listSubscribe webhook event is triggered when a recipient re-subscribes to a mailing list after unsubscribing from it. It is the counterpart of listUnsubscribe: the address has been removed from EmailEngine's suppression list for that listId, and your own subscriber records should follow.

When This Event is Triggered​

The listSubscribe event fires when:

  1. A recipient is on the suppression list for a listId
  2. They open the unsubscribe page for that list and confirm the re-subscribe action
  3. EmailEngine removes them from the suppression list

The re-subscribe action exists only on the unsubscribe page EmailEngine renders. There is no API or one-click equivalent, and removing an address through the Blocklists API or the admin interface does not fire the event.

It fires only when an entry was actually removed. If the address was not on the list, because it had never unsubscribed or had already re-subscribed, the page confirms the re-subscription but no webhook is sent.

Payload Schema​

Top-Level Fields​

FieldTypeRequiredDescription
serviceUrlstring or nullYesThe configured EmailEngine service URL. null when the serviceUrl setting is empty
accountstringYesAccount ID that sent the original message
datestringYesISO 8601 timestamp when the webhook was generated
eventstringYesAlways listSubscribe
dataobjectYesRe-subscribe details (see below)

Data Object Fields​

FieldTypeRequiredDescription
recipientstringYesEmail address that re-subscribed
messageIdstringNoMessage-ID of the message whose unsubscribe link led to the page. Absent when the link was generated from the admin interface rather than embedded in a message
listIdstringYesThe list the recipient was restored to
remoteAddressstringYesIP address the browser request came from, resolved as described under trackOpen
userAgentstringNoUser-Agent header of the browser request, when one was sent

There is no event ID in the body. EmailEngine sends it in the X-EE-Wh-Event-Id request header. See Delivery and Retries.

Example Payload​

{
"serviceUrl": "https://emailengine.example.com",
"account": "marketing",
"date": "2025-10-18T10:45:22.315Z",
"event": "listSubscribe",
"data": {
"recipient": "customer@company.com",
"messageId": "<newsletter-2025-10-001@marketing.example.com>",
"listId": "weekly-newsletter",
"remoteAddress": "203.0.113.42",
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36"
}
}

Example with Minimal Data​

A re-subscription through a link generated in the admin interface, so there is no originating message, from a client that sent no User-Agent:

{
"serviceUrl": "https://emailengine.example.com",
"account": "notifications",
"date": "2025-10-18T11:20:05.000Z",
"event": "listSubscribe",
"data": {
"recipient": "user@example.org",
"listId": "product-alerts",
"remoteAddress": "198.51.100.7"
}
}

How Re-subscription Works​

The unsubscribe page is the same signed URL that the message's List-Unsubscribe header points at, opened in a browser:

  1. Unsubscribe: the recipient confirms the unsubscribe on the page, or their mail client has already done it one-click. EmailEngine adds them to the suppression list and sends listUnsubscribe
  2. Confirmation: the page now shows that the address is unsubscribed, with a "Was this a mistake? Click here to re-subscribe." link
  3. Re-subscribe: the link opens a confirmation dialog showing the address. Confirming submits the form back to EmailEngine with the signed blob, so the account, list and recipient come from the signature, never from the browser
  4. Removal: EmailEngine removes the address from the suppression list for that listId
  5. Webhook: this event is sent if an entry was removed

The re-subscription affects that listId only. The recipient stays unsubscribed from any other list they left.

Handling the Event​

EmailEngine will send to the address again from this point, so restore it in your own records and in any external list service:

async function handleListSubscribe(event) {
const { data, date } = event;

await db.subscribers.updateOne(
{ email: data.recipient.toLowerCase() },
{
$set: {
[`lists.${data.listId}.subscribed`]: true,
[`lists.${data.listId}.resubscribedAt`]: new Date(date)
}
}
);

await db.subscriptionLogs.insertOne({
email: data.recipient,
listId: data.listId,
action: 'resubscribe',
messageId: data.messageId,
timestamp: new Date(date),
ipAddress: data.remoteAddress
});
}

Suppression List Management​

The entry is removed before the event is sent, so a handler that fails does not keep the address suppressed. Once the address is off the suppression list, future submissions with the same listId to that recipient are sent again. The list itself can be read and edited through the API:

Neither API call fires a webhook. See Suppression Lists for the full picture.

  • listUnsubscribe - Triggered when a recipient unsubscribes from a mailing list
  • messageSent - Triggered when a message is accepted for delivery

See Also​

  • Webhooks Overview - Configuring the webhook URL and the webhookEvents allowlist
  • Virtual Lists - Sending list mail with listId, and what the recipient sees on the unsubscribe page
  • Suppression Lists - Reading and editing the suppression lists this event updates
  • Blocklists API - Listing every suppression list on the instance