Double opt-in
Make new signups click a confirmation link before any marketing email reaches them
With double opt-in, a signup doesn't become a marketing recipient until they've clicked a confirmation link. That extra click is your defence against mistyped addresses, shared role inboxes, and submissions from people who never meant to opt in.
Everything hinges on {{subscribeUrl}} — a link Bitelio generates per contact and injects into any email you send. When the recipient clicks it, their subscribed flag becomes true and Bitelio emits a contact.subscribed event.
Setup
Create two templates
-
A Transactional template holding the confirmation message, with
{{subscribeUrl}}inside:<p>Hi {{firstName}}, please confirm your email to start receiving updates:</p> <p><a href="{{subscribeUrl}}">Confirm my email</a></p> -
A Marketing template for the welcome message that only goes out once they've confirmed.
The confirmation must be transactional
If a marketing template is aimed at a contact who isn't subscribed, the send is silently skipped. That's exactly why the confirmation email needs to be transactional: transactional sends ignore subscription state.
Trigger the signup from your backend
From your server, make two requests with your secret key (sk_*): first register the contact as unsubscribed, then track the event that kicks off the confirmation workflow.
curl https://api.bitelio.com/contacts \
-H "Authorization: Bearer sk_your_secret_key" \
-d '{ "email": "ada@example.com", "subscribed": false, "data": { "firstName": "Ada" } }'
curl https://api.bitelio.com/v1/track \
-H "Authorization: Bearer sk_your_secret_key" \
-d '{ "event": "signup.pending", "email": "ada@example.com", "subscribed": false }'Note that subscribed: false appears in both requests. Calling /v1/track on its own would still create the missing contact — but as a subscribed one, which undermines the whole double opt-in scheme. Hence the explicit contact creation first.
Workflow A: send the confirmation
Under Workflows → New workflow:
- Trigger:
EVENTonsignup.pending SEND_EMAILstep → transactional confirmation template
Turn it on.
Workflow B: welcome them after confirmation
Under Workflows → New workflow:
- Trigger:
EVENToncontact.subscribed SEND_EMAILstep → marketing welcome template
Turn it on. Because contact.subscribed is emitted on every opt-in — a {{subscribeUrl}} click, the preferences page, or an API update — this single workflow covers both fresh confirmations and contacts who resubscribe later.
Reminder if they don't confirm
Add a WAIT_FOR_EVENT step to Workflow A, right after the send:
- Event:
contact.subscribed - Timeout:
86400(24 hours)
If the timeout fires, send one reminder — again from a transactional template. Resist adding more: to mailbox providers (and to the recipient), a stream of "please confirm" emails reads as spam.