Automations

Send an email or call your webhook automatically when a subscriber is added

Overview

An automation runs a list of steps for one subscriber when its trigger fires. Use it for welcome emails, to tell your CRM about a new sign-up, or both.

Open Automations in your company sidebar, click New Automation, pick a trigger, add steps, then click Save and activate.

Info

Automations are part of the automation workflows plan feature. Emails sent by an automation count toward your plan's monthly email quota, like any campaign.

Triggers

Subscriber added

Fires when a subscriber is added to your company, however they got there:

  • created in the dashboard or through the API (including API keys)
  • imported with bulk JSON or a CSV file
  • signed up on your public subscribe page (see the note on double opt-in below)
  • saved automatically when you send to receivers

Only for these lists (optional). Pick one or more lists to limit the automation to subscribers on those lists. With lists picked, the automation also runs when an existing subscriber is added to one of them later.

Note

Each automation runs once per subscriber. Editing a subscriber, re-importing them, or removing and re-adding them to a list does not start it again.

Tip
Subscribers from the public subscribe page must confirm their email first (double opt-in). The automation runs when they click the confirmation link, not when they submit the form.

An automation only runs while its status is Active. Draft and paused automations ignore new subscribers, and subscribers added while an automation was paused are not picked up when you activate it again.

Other triggers

Tag added, Email opened, Link clicked, Date based and Webhook trigger are marked Coming soon. You can save drafts with them, but they can't be activated yet.

Steps

An automation can have up to 10 steps. They run in order. If a step fails, the run stops and later steps don't run. If a step is skipped (for example, the address is suppressed), the run continues with the next step.

Send email

Sends one of your templates. By default it goes to the subscriber who triggered the automation. It can also go to fixed addresses, such as your own team.

SettingRequiredDescription
Send toYesThe subscriber who triggered this (default) or Specific addresses
ToWith specific addresses1 to 5 fixed addresses
CC, BCCNoUp to 5 addresses each, in either mode. Click Add CC / BCC to show them
TemplateYesOne of your company's templates
Sending configurationNoOne of your SMTP configurations. If you leave it on Company default, your most recently added configuration is used
Subject overrideNoReplaces the template subject. Variables work here too
From nameNoReplaces the sender name of the sending configuration

A step can send to at most 10 addresses in total. When it sends to the subscriber, the subscriber counts as one of them. Addresses are trimmed, lowercased and sent once each, even if you list the same address in To and CC. When the step sends to the subscriber, their own address is removed from CC and BCC.

CC addresses are visible to everyone who receives the email. BCC addresses are delivered without appearing in the email headers.

When the step sends to the subscriber and has CC or BCC, it sends two emails:

  1. The subscriber's own email, to the subscriber alone. It has the usual unsubscribe link, and it doesn't show the CC or BCC addresses.
  2. A separate copy for the CC and BCC recipients, with the same subject and content. CC addresses are visible on the copy and BCC addresses aren't. The subscriber is not on the copy.

Templates can use these variables:

VariableValue
[[email]]Subscriber email
[[first_name]], [[last_name]], [[full_name]]Subscriber name
[[company_name]]Your company name
[[unsubscribe_url]], [[preferences_url]], [[view_in_browser_url]]Links for this email
any custom field, e.g. [[plan]]The subscriber's extra_fields
Info

Variables always describe the subscriber who triggered the automation, including in emails sent to specific addresses. That makes alerts possible: send yourself "New subscriber: [[email]]".

Unsubscribe links. When the email goes to the subscriber, it gets a List-Unsubscribe header, as with campaigns. If the template doesn't contain the unsubscribe link, a footer with that link is added. Emails sent to specific addresses are internal, so they get no unsubscribe footer and no List-Unsubscribe header. In those emails, [[unsubscribe_url]] and [[preferences_url]] become #, so your team can't unsubscribe the subscriber by mistake.

Info
CC and BCC recipients get a separate copy without the subscriber's unsubscribe link, and the subscriber's email doesn't show them. In that copy, as in emails sent to specific addresses, there is no unsubscribe footer or `List-Unsubscribe` header, and `[[unsubscribe_url]]` and `[[preferences_url]]` become `#`.

Quota and limits. Every address (the subscriber, To, CC and BCC, across both emails) counts toward your monthly email quota and the sending configuration's hourly and daily limits, and each one appears in your sent email history. SentinMail checks the total before sending anything: if the quota left is smaller than the number of addresses, nothing is sent (not even the subscriber's email) and the step fails.

If the subscriber's email goes out but the CC/BCC copy fails, the step is marked as failed, and the run history shows which email was sent. If the step runs again, the subscriber's email is not sent a second time.

Skipped addresses.

  • When the step sends to the subscriber, it is skipped if the subscriber's address is on your suppression list or they haven't confirmed. The CC/BCC copy is skipped too, because it never goes out on its own.
  • Suppressed addresses in To, CC or BCC are removed one by one and listed in the run history. If every To address is suppressed, the step is skipped. If every CC and BCC address is suppressed, only the copy is dropped.
  • In either mode, the step is skipped if the subscriber has left every list the automation is limited to.

The step fails when your monthly quota is used up or your subscription is inactive. If the sending configuration's hourly or daily limit is reached, the run waits and continues when the limit resets.

Example: welcome email plus a sign-up alert

An automation with the trigger Subscriber added and two email steps:

  1. Send to: the subscriber who triggered this. Template: "Welcome". The subscriber gets their welcome email, with the usual unsubscribe link.
  2. Send to: specific addresses. To: founders@yourcompany.com. BCC: crm-inbox@yourcompany.com. Template: "New sign-up alert". Subject override: New subscriber: [[email]].

The alert template can show the subscriber's details:

Code
html
1<p>[[first_name]] [[last_name]] ([[email]]) just signed up.</p>
2<p>Plan: [[plan]]</p>

In the API, the second step looks like this:

Code
json
1{
2 "type": "send_email",
3 "config": {
4 "recipient": "custom",
5 "to": ["founders@yourcompany.com"],
6 "bcc": ["crm-inbox@yourcompany.com"],
7 "template_id": "TEMPLATE_ID",
8 "subject": "New subscriber: [[email]]"
9 }
10}

Steps saved before these options existed have no recipient field. They keep sending to the subscriber.

Webhook

Sends an HTTP POST with a JSON body to your URL.

SettingRequiredDescription
URLYesA public http or https URL
HeadersNoExtra headers, for example Authorization: Bearer ...
Include in payloadNoChoose whether to send the subscriber's custom fields and lists. Both are sent by default

Header values are stored encrypted. After you save them, they are never shown again (the dashboard and the API show ********). To change a value, type a new one. Host, Content-Length, Content-Type, Transfer-Encoding, Connection and other hop-by-hop headers can't be set, and neither can headers that start with X-Sentinmail-.

Warning
For security, webhook URLs must point to the public internet. URLs that resolve to private, loopback, link-local (including `169.254.169.254`) or other reserved addresses are refused, both when you save and when the request is sent. Redirects are not followed: a `3xx` response counts as a failure.

Delivery. Each request times out after 10 seconds. Network errors and 5xx responses are retried up to 3 times (after 1, 2 and 4 seconds). 2xx means success. Any other status fails the step straight away. SentinMail reads at most 64 KB of your response and keeps the first 500 characters in the run history.

Payload

Code
json
1{
2 "event": "subscriber_added",
3 "automation": { "id": "7b1e...", "name": "Welcome series" },
4 "subscriber": {
5 "id": "3f2a...",
6 "email": "jane@example.com",
7 "first_name": "Jane",
8 "last_name": "Doe",
9 "extra_fields": { "plan": "pro" },
10 "lists": [{ "id": "9c4d...", "name": "Newsletter" }]
11 },
12 "company": { "id": "51e0..." },
13 "sent_at": "2026-10-17T09:30:00.123456Z"
14}

Request headers

HeaderValue
Content-Typeapplication/json
User-AgentSentinMail-Webhook/1.0
X-Sentinmail-Eventsubscriber_added
X-Sentinmail-Delivery<run id>.<step index>. It stays the same across retries, so you can use it to drop duplicates
X-Sentinmail-Signaturesha256=<hex HMAC-SHA256 of the raw body>

Verify the signature

Each automation has its own signing secret (it starts with whsec_). It is shown once when you create the automation. Later, open the automation's Steps tab and click Reveal to see it. Rotate replaces it, and after that, requests signed with the old secret no longer verify.

Compute the HMAC over the raw request body exactly as it arrived (don't parse and re-serialize the JSON first), then compare it to the header in constant time.

Code
python
1import hashlib
2import hmac
3 
4def is_valid(raw_body: bytes, signature_header: str, secret: str) -> bool:
5 expected = 'sha256=' + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
6 return hmac.compare_digest(expected, signature_header or '')
7 
8# Django: is_valid(request.body, request.headers.get('X-Sentinmail-Signature'), SECRET)
Code
javascript
1const crypto = require('crypto');
2 
3// Use express.raw({ type: 'application/json' }) so req.body is a Buffer.
4function isValid(rawBody, signatureHeader, secret) {
5 const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
6 const a = Buffer.from(expected);
7 const b = Buffer.from(signatureHeader || '');
8 return a.length === b.length && crypto.timingSafeEqual(a, b);
9}
Tip
To reject replayed requests, also check that `sent_at` is recent (for example, within 5 minutes) and that you haven't seen the `X-Sentinmail-Delivery` value before.

Activation checks

When you activate an automation, SentinMail checks that:

  • the trigger is available (not Coming soon)
  • there is at least one step
  • every email step has a template from your company, and a sending configuration (either one you picked or your company default)
  • every email step that sends to specific addresses has at least one To address, and all addresses are valid and within the limits
  • every webhook step has a public URL and valid headers
  • the selected lists belong to your company

If any check fails, the automation stays inactive and the errors appear next to the fields that need fixing. The same checks run when you save changes to an automation that is already active.

Run history

Open an automation and go to the Runs tab, or click the history icon in the automations list. Each run shows the subscriber, its status and when it ran. Click a run to see the result of each step:

Run statusMeaning
pendingWaiting to start, or waiting for a sending limit to reset
runningSteps are being processed
completedEvery step finished (some may have been skipped)
failedA step failed. The error tells you which one and why
skippedThe run didn't start, for example because the automation was paused before it ran

For email steps, the result lists each email the step sent (the subscriber's email and the CC/BCC copy, or the email to specific addresses) with its recipients and status, any suppressed addresses that were removed, and the Message-ID. For webhook steps, it shows the HTTP status, how many attempts were made, and the start of your response.

Run history is also available from the API, newest first and paginated:

Code
bash
1curl "https://api.sentinmail.app/api/emails/automations/AUTOMATION_ID/runs/?company=COMPANY_ID&page=1" \
2 -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Note
Automation endpoints are for signed-in team members only. API keys can't manage automations or read their runs.
automationsworkflowstriggerswebhookswelcome emails