EventTrigger icon
OutputValues icon
If icon
SlackIncomingWebhook icon
Log icon

Sent Message Delivery Confirmation Gate

React to Sent message events in real time, alert Slack when delivery is not confirmed, and log the result for messaging platform teams.

Categories
Business

A transactional message that silently fails to deliver looks identical to a slow network until someone notices the recipient never got it. Sent reports every lifecycle event through a signed webhook, but nothing downstream of that webhook decides whether a given event means the message actually arrived. This blueprint verifies every message-family event against the one state that actually means success, DELIVERED, and pages the moment anything else shows up.

This blueprint was created by Mohit Jeswani.

How it works

  1. sent_message_events (io.kestra.plugin.sent.triggers.EventTrigger) receives signed Sent webhook events scoped to the message event family, verifying the HMAC-SHA256 signature in constant time before this flow ever sees the payload.
  2. evaluate (io.kestra.plugin.core.output.OutputValues) reads message_id and message_status from the verified event payload and classifies DELIVERED as OK, a missing status as CRITICAL, and any other status as DELIVERY_NOT_CONFIRMED.
  3. route (io.kestra.plugin.core.flow.If):
    • compliant: logs the confirmed delivery.
    • alert: posts the message id, event name, and real status to Slack.
  4. summary logs the message id and severity for every event, closing the governance cycle.
  5. errors alerts Slack if the flow itself fails, for example a webhook signature verification configuration error.

What you get

  • A delivery check built on Sent's own signed event payload, not a polling script guessing at whether a message arrived.
  • A real distinction between a confirmed DELIVERED status and everything else, without assuming the exact name of every possible failure state Sent might ever send.
  • A Slack alert naming the real message id and the real status Sent reported, never an invented one.

Who it's for

  • Messaging and platform teams sending transactional messages through Sent who want non-delivery caught the moment the webhook fires, not discovered when a customer says they never got the message.
  • Teams evaluating the Sent plugin who want a worked example of EventTrigger and its signature verification used as a standing delivery gate, the first blueprint in this repo to use this plugin at all.

Why orchestrate this with Kestra

Sent delivers a signed webhook for every event; it does not decide which status counts as success, compare it against expectations, or notify a Slack channel when delivery is not confirmed. Kestra verifies the signature, classifies the real status, turns an unconfirmed delivery into a Slack page naming the exact message id, and keeps a full execution history of every event received.

Prerequisites

  • A Sent account with at least one webhook configured against this flow's generated Kestra webhook URL, subscribed to message events.
  • The webhook's signing secret, prefixed whsec_, from Sent's webhook settings.
  • A Slack incoming webhook URL.

Sent delivers events to a real, internet-reachable HTTPS endpoint; there is no official local Sent emulator, so sent_message_events cannot be exercised by replaying events against a local Docker container without a tunnel (e.g. ngrok) exposing the Kestra webhook URL during testing.

Secrets

  • SENT_WEBHOOK_URL_KEY: the key segment of this flow's generated Kestra webhook URL. In Kestra OSS, provide it as the base64-encoded environment variable SECRET_SENT_WEBHOOK_URL_KEY.
  • SENT_WEBHOOK_SIGNING_SECRET: the whsec_-prefixed signing secret from Sent. In Kestra OSS, provide it as the base64-encoded environment variable SECRET_SENT_WEBHOOK_SIGNING_SECRET.
  • SLACK_WEBHOOK_URL: used by alert and the errors block. In Kestra OSS, provide it as the base64-encoded environment variable SECRET_SLACK_WEBHOOK_URL.

Outputs

  • {{ trigger.event }} / .field / .payload / .timestamp: the verified Sent event, as EventTrigger reports it.
  • {{ outputs.evaluate.values.message_id }} / .message_status: the message id and real status from the event payload.
  • {{ outputs.evaluate.values.severity }}: OK, DELIVERY_NOT_CONFIRMED, or CRITICAL.

Pitfalls

  • events: [message] matches on the event's parent field, so this trigger fires for every message-family event Sent sends (for example a message.received event with no message_status at all), not only delivery-outcome events; a missing message_status is classified CRITICAL rather than silently ignored, since that is itself worth seeing.
  • DELIVERED is the only status this gate treats as success; an intermediate state like SENT or QUEUED is real and expected mid-flight, but still alerts if the event you are looking at is the last one Sent ever sends for that message, since this gate has no way to know whether a later DELIVERED event is still coming.
  • tolerance (webhook replay tolerance) defaults to 5 minutes; a webhook delivered later than that against a stale X-Webhook-Timestamp is rejected as unauthorized rather than processed, which is a security control, not a bug, if Sent's own retries are delayed.

Quick start

  1. Add the SENT_WEBHOOK_URL_KEY, SENT_WEBHOOK_SIGNING_SECRET, and SLACK_WEBHOOK_URL secrets.
  2. Deploy this flow and copy its generated Kestra webhook URL.
  3. Register that URL in Sent's webhook settings, subscribed to message events, and copy the resulting signing secret back into SENT_WEBHOOK_SIGNING_SECRET.
  4. Send a real test message and confirm compliant fires once Sent reports it DELIVERED.
  5. Send a message to an invalid recipient to confirm alert fires on the resulting non-DELIVERED status.

How to extend

  • Persist dedupeKey from the trigger output in a KV entry to deduplicate retried webhook deliveries across executions, as the plugin's own documentation recommends.
  • Add a second If branch keyed on trigger.event to treat message.received (an inbound event, not a delivery outcome) differently from an outbound delivery event.
  • Chain io.kestra.plugin.sent.messages.GetMessageActivities in the alert branch to pull the message's full delivery history before paging, for richer context than the single event.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.