Sending
An e-mail goes out when you write to its status endpoint. This page covers production and test sends, the checks novem runs before a send is accepted, and how to follow up with status, stats and the log.
AI assisted, human approved — novem uses AI to review and keep our documentation up to date.
Sending is a single write: POST the word sent to the e-mail's status
file and novem queues a delivery to every valid entry in the
recipients folder.
sent
A successful trigger answers 202 Accepted; delivery itself is
asynchronous. Only the owner of an e-mail can send it.
Write test instead and the rendered e-mail goes to exactly one address:
your own registered and verified one. Recipient lists, the config/enabled
switch and the send rate limit are all bypassed, which makes test the safe
way to iterate on content:
# send a test of the current draft to yourself
novem -m weekly_report -w status test
# happy? send it for real
novem -m weekly_report -w status sent
Note: with the bare-word body, anything that does not start with test
is treated as a production send request. For finer control, including ad-hoc
recipients, use the JSON body described next.
The status file also accepts a JSON body. This generalises the trigger and
lets you supply the recipients inline, instead of maintaining the
recipients folder ahead of time:
{ "action": "send", "to": ["alex@example.com", "sam@example.com"] }
The to addresses replace the e-mail's stored recipient list for that one
send; the stored list itself is left untouched. Only the to vector is
supported: ad-hoc sends take direct addresses, not cc, bcc, @user handles
or groups. The content, subject and theme still come from the e-mail itself, so
an ad-hoc send changes only who receives this particular delivery.
action selects the send type and defaults to send. { "action": "test" }
is the JSON equivalent of the bare test word, and { "action": "send" } with
no to array behaves exactly like the bare sent word: a normal send to the
stored recipients.
Ad-hoc addresses count against your plan's
direct-address allowance
and pass through the same unsubscribe and bounce suppression as stored
recipients. A malformed body, an unknown action, a non-array to, an empty
to, or an invalid address is rejected with 400.
Note: the in-flight and rate-limit checks below are scoped to the recipient set for an ad-hoc send. Sending the same e-mail to a different address in a second call is accepted right away; only an identical re-fire to the same recipients within the in-flight window is held back.
Novem validates a send request before queueing it. The full list, in order:
| Check | Failure response |
|---|---|
| You own the e-mail | 404 |
| Your own e-mail address is verified | 403 |
| No send of this e-mail is already in flight | 425 — try again once it completes |
| At most 10 sends of the same content per 30 minutes | 429 with retry_after_seconds in the body |
config/enabled is not set to a falsy value | 403 — see config |
The rate limit is content-based: editing the e-mail (or anything it embeds)
resets the window, so iterating on a report never runs into it. Only
re-sending the identical e-mail does. For ad-hoc sends
the window also keys on the recipient set, so the same e-mail to different
addresses counts independently. Test sends are exempt from both the rate limit
and the enabled check.
Recipient lists are resolved at send time, and your plan's recipient limits are applied to the resolved list.
GET on the same endpoint tells you where the e-mail is in its lifecycle:
| Value | Meaning |
|---|---|
ready | No send in progress; the e-mail can be sent |
sending | A production send is being processed |
testing | A test send is being processed |
GET /v1/vis/mails/:mail/stats/runs returns one row per send with the
timestamp, duration in seconds, and final status: plain text by default, JSON
with an Accept: application/json header.
Everything that happens to an e-mail (recipient changes, send triggers, rejected sends and the reason why) is recorded in its log:
novem -m weekly_report -r log
# or
curl -H "Authorization: Bearer $NOVEM_TOKEN" \
https://api.novem.io/v1/vis/mails/weekly_report/log
When a send doesn't behave the way you expect, the log is the first place to look.