Lifecycle emails (the CRM module's automations) send through Resend and need a verified sending domain plus a webhook, in addition to the API key you already set for transactional email in the admin panel.
Verify the sending domain
In the Resend dashboard, add the domain you send from and create the DNS records it shows you at your DNS provider:
- SPF — a
TXTrecord authorizing Resend to send on the domain's behalf. - DKIM — one or more
CNAMErecords Resend uses to sign outgoing mail. - DMARC — a
TXTrecord at_dmarc.<domain>; Resend does not require it to send, but mailbox providers weigh it heavily, and skipping it is the most common cause of lifecycle emails landing in spam.
Resend marks the domain verified once the records propagate, usually within minutes.
Configure the sender
Set the Resend API key and the sender email/name in the admin panel's /email-delivery
page — the same place that already configures transactional email. Nothing in .env
controls the sender identity.
Wire the delivery webhook
Lifecycle automations track opens, clicks, bounces and complaints through a webhook, and auto-suppress an address after a bounce or complaint. Without it, delivery status in the CRM screens never updates and bouncing addresses keep getting emailed.
- In Resend, add a webhook endpoint pointing at
POST https://<your-api-domain>/api/v1/internal/crm/resend-webhook, subscribed to theemail.delivered,email.bounced,email.complained,email.openedandemail.clickedevents. - Copy the signing secret Resend shows you (
whsec_<base64>) intoRESEND_WEBHOOK_SECRET.
An empty RESEND_WEBHOOK_SECRET makes the endpoint reject every request with 503, so no
event updates crm_email_send_logs until it is set.
Unsubscribe
Every lifecycle email carries a one-click unsubscribe link (RFC 8058) pointing at the web
app's public /crm/unsubscribe page — no login required. Clicking it suppresses that address
for lifecycle automations immediately; it does not affect transactional email.