Unsubscribe Links and Webhook Handlers
NotifiedBy can add an unsubscribe link into outgoing emails and notify your own application when a recipient clicks that link.
This page documents two parts of that integration:
how to place the unsubscribe placeholder in email content
how to build a webhook handler in your client application
Adding the unsubscribe link
Each sender can be configured with an unsubscribe link text and an unsubscribe webhook URL.
The unsubscribe placeholder is:
[[notifiedby:unsubscribe]]
You can now use this placeholder in either of these places:
the sender’s unsubscribe template/footer text
the email HTML content itself
When NotifiedBy sends the email, it replaces [[notifiedby:unsubscribe]] with a real unsubscribe
anchor tag for that recipient.
Example footer text:
Manage your preferences here: [[notifiedby:unsubscribe]]
Example HTML body content:
<p>If you no longer want these alerts you can [[notifiedby:unsubscribe]] at any time.</p>
The visible text of the link is controlled by the sender’s
unsubscribe_link_text setting. For example, if the link text is set to
unsubscribe, the rendered email will contain a link such as:
<a href="https://...">unsubscribe</a>
The rendered unsubscribe link also includes a CSS class name:
<a class="unsubscribe-link" href="https://...">unsubscribe</a>
This lets you style the link in your own HTML email content or master layout. For example:
<style>
.unsubscribe-link {
color: #666666;
font-size: 12px;
text-decoration: underline;
}
</style>
Note
The [[notifiedby:unsubscribe]] placeholder is intended for HTML email content. NotifiedBy
replaces it with an HTML anchor tag using the unsubscribe-link CSS class.
What happens when a recipient unsubscribes
When the recipient clicks the generated unsubscribe link:
NotifiedBy validates the unsubscribe token.
The recipient is added to the sender’s blocked list.
An unsubscribe event is recorded.
NotifiedBy attempts to call the sender’s configured unsubscribe webhook.
The unsubscribe is applied inside NotifiedBy before the client webhook delivery is attempted. This means the recipient is still suppressed in NotifiedBy even if your application is temporarily unavailable.
Configuring the unsubscribe webhook URL
The sender’s unsubscribe_webhook field should contain a URL template. The
following placeholders are supported:
{sender_slug}— the sender identifier{email}— the unsubscribed email address, URL-encoded
Example:
https://client.example.com/integrations/notifiedby/unsubscribe/?sender={sender_slug}&email={email}
At delivery time, NotifiedBy replaces those placeholders and sends a POST
request to the final URL.
Important
The current webhook delivery format is a POST request with the useful
values placed in the URL query string. Your handler should therefore read
sender and email from the query parameters. The sender parameter
contains the NotifiedBy sender slug.
Building a webhook handler in your client application
A good client application webhook endpoint should:
accept
POSTrequestsread
senderfrom the query stringread
emailfrom the query stringfind the correct tenant, integration, sender or mailbox mapping
mark that contact unsubscribed in your own database
return
200 OKonce the action has been applied successfullybe idempotent, so repeated calls for the same email do not cause errors
Why idempotency matters
NotifiedBy may retry a failed webhook delivery. Your endpoint should therefore behave safely if the same unsubscribe arrives more than once.
For example, if a user is already marked unsubscribed, your endpoint should still return success instead of treating the second call as an error.
Minimal Django example
The following example shows a simple Django view for handling the callback.
from django.http import HttpResponseBadRequest, JsonResponse
from django.views.decorators.http import require_POST
@require_POST
def notifiedby_unsubscribe(request):
sender = request.GET.get("sender")
email = request.GET.get("email")
if not sender or not email:
return HttpResponseBadRequest("Missing sender or email")
# The `sender` query parameter contains the NotifiedBy sender slug.
# Example integration lookup:
# integration = NotifiedByIntegration.objects.get(sender_slug=sender)
# contact = Contact.objects.filter(
# organisation=integration.organisation,
# email__iexact=email,
# ).first()
# if contact:
# contact.is_unsubscribed = True
# contact.save(update_fields=["is_unsubscribed"])
return JsonResponse({"ok": True})
Example URL configuration:
from django.urls import path
from .views import notifiedby_unsubscribe
urlpatterns = [
path(
"integrations/notifiedby/unsubscribe/",
notifiedby_unsubscribe,
name="notifiedby-unsubscribe",
),
]
Response expectations
NotifiedBy currently treats the webhook as successfully delivered only when your
endpoint returns HTTP 200.
For best compatibility, your handler should:
return
200after applying the unsubscribeavoid redirects
avoid returning
202or204if you want NotifiedBy to mark the event as delivered immediately
Operational troubleshooting
If unsubscribe callbacks are not reaching your application, check:
the sender has an
unsubscribe_webhookconfiguredthe configured URL template is valid
your endpoint is publicly reachable by NotifiedBy
your endpoint accepts
POSTrequestsyour endpoint reads the values from the query string
your endpoint returns HTTP
200