Sending and delivery
Authoring a template is one half of email. This is the other: what your organization has to set up once, what every individual send is checked against, and where you look when someone says they did not get it.
Your sending domain
Section titled “Your sending domain”Until you verify a domain, sends go out from a shared fallback domain. That works for development and for a first look, and it is the wrong thing to grow on: mail from a domain you own is what reputation, alignment, and replies all depend on.
Claim the domain, install the DNS records Cowliss gives you, and the status follows on its own:
cow domains create --domain mail.example.comcow domains list # find the dom_ id of the domain you just claimedcow domains get dom_… # the records to install, each with its own statuscow domains verify dom_… # re-check now instead of waitingThe record table covers signing keys, the return path for bounces, and a recommended policy record. A claim is exact and global, so a domain a neighbour of yours already verified conflicts rather than silently sharing. Verification is checked when a send is prepared, so a domain that falls out of verification stops sends with a typed skip instead of sending unsigned mail.
The gates every send passes
Section titled “The gates every send passes”A send call is an attempt. It is evaluated the moment it runs, in this order, and the first gate that stops it decides the outcome:
| Gate | What it asks |
|---|---|
| Journey enabled | Is this journey turned on in this environment? |
| Sending paused | Is your organization’s sending paused? |
| Suppressed | Is this address on the suppression list? |
| Credit | Does the organization have credit left? |
| Frequency cap | Has this person already had 5 marketing emails in the last rolling day? |
| Consent | Has this person consented to the journey’s purpose? |
| Sending domain | Is there a usable verified domain, or the fallback? |
A transactional template skips the frequency cap and the consent gate by design, because a receipt is not something anyone opted into. Every other gate still applies to it. See Email templates for how a template declares its class.
Evaluating at send time rather than at trigger time is deliberate: someone who unsubscribes on day two of a five-day journey is respected on day two, without anyone cancelling the execution.
A stopped send does not throw. The call resolves with a skipped_* status, so a journey keeps its shape, and the reason is on the delivery row.
The suppression list
Section titled “The suppression list”An address lands on the suppression list when mail to it hard-bounces or when the recipient marks a message as spam. Every later send to that address is skipped before it costs anything, and the dashboard can say why.
Suppression and consent are separate facts. A complaint revokes consent (that person asked to stop hearing from you) and suppresses the address. A hard bounce only suppresses it: the address does not work, which says nothing about what the person wanted.
cow suppressions delete sup_… # admin onlyRemoving an entry is a deliberate admin action, for the case where you know the address was fixed. It is not a way around a complaint.
Unsubscribing
Section titled “Unsubscribing”Marketing mail carries the headers that put a one-click unsubscribe button in the recipient’s mail client, and the endpoint behind it revokes consent for the purpose the mail was sent under. That is the same consent flag the gate above reads, so the next journey to try is stopped for the right reason rather than by a filter you maintain.
Consent lives on the profile and you own it. You can set it from identify, and you should when your own signup form is where the person actually agreed. See Data protection.
The delivery log
Section titled “The delivery log”Every attempt writes one row, whether it went out or not:
| Status | Meaning |
|---|---|
sent |
Handed off to the mail provider. |
delivered |
Accepted by the recipient’s server. |
bounced |
Rejected. A hard bounce also suppresses the address. |
complained |
Marked as spam. Outranks a bounce, and revokes consent. |
failed |
Cowliss could not attempt it. |
skipped_* |
A gate stopped it: skipped_disabled, skipped_paused, skipped_suppressed, skipped_quota, skipped_frequency_cap, skipped_consent, skipped_domain, skipped_ssrf. |
would_* |
A dry run. Nothing was sent. |
A late delivered never overwrites a bounced, so a row’s final status is the truthful one. Webhooks share the log: a 2xx from your endpoint is its confirmation, and it is terminal at delivered.
cow deliveries list --status bounced --since 2026-09-01T00:00:00Zcow deliveries list --journey abandoned-checkout --channel emailcow deliveries get dlv_…The delivery log is the answer to “did they get it”, and the execution page is the answer to “why did the journey send it”. Both are per environment, so a development run is never mixed into your production numbers.
Development sends
Section titled “Development sends”Sends from the development environment are captured rather than delivered, which is what makes it safe to run a whole journey against a real-looking profile. See Environments and Testing journeys.
Reference
Section titled “Reference”- Sending domains: claim, DNS records, verification status.
- Deliveries: the log, its filters, and the public feedback and unsubscribe endpoints.
- Suppressions: listing and removal.