Email

Email marketing

Send a one-off broadcast email to a segment of your project's users, such as verified, new, active or dormant users, through your project's SMTP.

Email marketing sends a single subject and body to a group of your project's end users, chosen by a built-in segment. OrbitNest finds the recipients on the server and sends in the background through your project's SMTP. Only workspace admins can send, from Studio or with the admin API.

Requires project SMTP

Broadcasts always go through the project's own SMTP. The shared OrbitNest sender only carries auth emails. Without SMTP, a broadcast starts but every recipient fails.

Who receives broadcasts

Recipients come from your project's auth_users table, meaning the people who signed up to your app. Deleted users, banned users, users without an email address and unsubscribed addresses are always skipped. You cannot upload or paste your own list of recipients.

Segments

SegmentStudio labelWho it includes
allAll usersEvery user, verified or not
verifiedVerifiedUsers who confirmed their email
unverifiedUnverifiedUsers who never confirmed their email
recent_signups_7dNew (7 days)Users created in the last 7 days
recent_signins_7dActive (7 days)Users who signed in within the last 7 days
inactive_30dDormant 30+Verified users with no sign-in in the last 30 days, including verified users who never signed in
inactive_60dDormant 60+The same, for 60 days
inactive_90dDormant 90+The same, for 90 days
never_signed_inNever signed inUsers who never signed in

Segments are worked out when you send, so they always reflect current data. Each broadcast reaches at most 10,000 recipients. If a segment is larger, only the 10,000 most recently created users receive it.

Send from Studio

Open your project and go to Settings → Marketing.

  1. Audience: pick a segment. Studio shows how many recipients it matches, a sample of their addresses, and how many were left out because they unsubscribed.
  2. Template: optionally start from Announcement, Newsletter, Re-engagement or Custom. Each one fills in a sample subject and HTML body.
  3. Message: edit the Subject, the HTML body (use inline styles) and an optional Plain-text fallback.
  4. Click Send broadcast, review the recipient count, and confirm. OrbitNest adds an unsubscribe link to the footer of every email.

The broadcast runs in the background. When it finishes you can see how many emails were sent and how many failed, with the failure reasons.

Caution

A broadcast cannot be stopped or undone once it starts. Check the recipient count and sample before you confirm.

Send with the API

These endpoints use a Studio admin access token, which is the access_token returned by POST /api/auth/signin. :projectId must be the project UUID.

MethodPathRoleDescription
GET/api/admin/projects/:projectId/email/audience?segment=<segment>&limit=<n>Any memberCount the recipients of a segment and return up to 50 sample addresses, without sending. limit must be a positive integer
POST/api/admin/projects/:projectId/email/broadcastAdminStart a broadcast, or do a dry run. Limited to 10 requests per minute per IP address
GET/api/admin/projects/:projectId/email/broadcast/:jobIdAny memberProgress and result of a broadcast
GET/api/admin/projects/:projectId/email/suppressions?search=<text>&limit=<n>Any memberList unsubscribed addresses, newest first. limit is 1 to 1,000 (default 200)
DELETE/api/admin/projects/:projectId/email/suppressions/:emailAdminRemove an address from the unsubscribe list. Returns 404 if it is not on the list

Preview the audience

Terminal
curl "https://api.orbitnest.io/api/admin/projects/$PROJECT_ID/email/audience?segment=inactive_30d" \
  -H "Authorization: Bearer $ORBITNEST_ADMIN_TOKEN"
JSON
{
  "success": true,
  "data": {
    "recipientCount": 128,
    "sampleRecipients": ["ana@example.com", "li@example.com"],
    "suppressedCount": 3
  }
}

suppressedCount is the number of segment members left out because they unsubscribed.

Send a broadcast

FieldTypeRequiredDescription
segmentstringYesOne of the segments above. Any other value returns 400
subjectstringYesThe subject line, up to 998 characters
htmlstringYesThe HTML body
textstringNoA plain-text alternative
dryRunbooleanNoIf true, finds the recipients and returns them without sending
limitintegerNoThe maximum number of recipients, 1 to 10,000

Unknown fields return 400.

Terminal
curl -X POST "https://api.orbitnest.io/api/admin/projects/$PROJECT_ID/email/broadcast" \
  -H "Authorization: Bearer $ORBITNEST_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "segment": "inactive_30d",
    "subject": "Here is what is new in My App",
    "html": "<p>We shipped a lot since your last visit. Come take a look.</p>",
    "text": "We shipped a lot since your last visit. Come take a look."
  }'

A real send returns 202 Accepted right away with a job:

JSON
{
  "success": true,
  "data": {
    "jobId": "3c9a1f2e-7b4d-4c1a-9e0f-5d2b8a6c4e11",
    "status": "running",
    "startedAt": "2026-10-12T09:30:00.000Z",
    "finishedAt": null,
    "segment": "inactive_30d",
    "recipientCount": 128,
    "sampleRecipients": ["ana@example.com", "li@example.com"],
    "sent": 0,
    "failed": 0,
    "errors": [],
    "dryRun": false,
    "suppressedCount": 3
  }
}

A dry run, or a segment with no recipients, returns 200 with the same fields but no job (jobId, status, startedAt and finishedAt are left out). recipientCount never includes unsubscribed addresses.

Check progress

Poll the job until status is completed:

Terminal
curl "https://api.orbitnest.io/api/admin/projects/$PROJECT_ID/email/broadcast/$JOB_ID" \
  -H "Authorization: Bearer $ORBITNEST_ADMIN_TOKEN"

The response has the same shape (without suppressedCount), with sent and failed counting up and finishedAt set at the end. If someone unsubscribes while the broadcast is sending, they are skipped and recipientCount goes down by one. errors lists up to 200 failures as { "email", "reason" }. sampleRecipients lists at most 50 addresses. An unknown job returns 404. Finished jobs are kept for 30 days.

When a broadcast is refused

POST .../email/broadcast returns 409 Conflict when:

  • another broadcast is still sending for the project, or
  • the same subject, HTML, text and segment were already delivered to at least one recipient in the past hour. Change the content to send again.

Unsubscribe

Every broadcast email gets:

  • an Unsubscribe link at the end of the HTML body (and of the plain-text body, if you sent one), and
  • the List-Unsubscribe and List-Unsubscribe-Post: List-Unsubscribe=One-Click headers, so mail apps such as Gmail and Apple Mail can show their own unsubscribe button.

Both point to https://api.orbitnest.io/api/email/unsubscribe?token=<token>. The server signs the token, and it is tied to one project and one address, so nobody can guess it or change it to unsubscribe someone else.

  • Opening the link (GET) shows a confirmation page with an Unsubscribe button. Opening it alone does not unsubscribe, because email security scanners open links automatically.
  • POST to the same URL unsubscribes. The button and the mail apps' one-click button both do this. It returns { "success": true, "data": { "unsubscribed": true } }, or a confirmation page for a browser. Repeating it is harmless.
  • An invalid or edited token returns 400.
  • The endpoint needs no login and is limited to 120 requests per minute per IP address.

Unsubscribing applies to one project's broadcasts only. Sign-in codes, verification, password-reset and welcome emails, and emails sent with the Email API, are not affected.

To see who unsubscribed, open Settings → Marketing and click View list under Unsubscribed. Admins can remove an address there (for example, when the person asks to hear from you again), and the address receives the next broadcast.

Delivery behavior

  • Each broadcast keeps up to four connections open to the project's SMTP server and sends four emails at a time over them. If one recipient fails, the rest are still sent.
  • If SMTP is not configured or is turned off, every recipient fails.
  • Every message uses the project's From address, with Reply-To set to the From Email.
  • Jobs and their recipient lists are stored in the database. If the API restarts or is redeployed while a broadcast is sending, the broadcast continues from where it stopped and skips everyone who already got it. Only one API server sends a given broadcast at a time.
  • If an API server crashes in the middle of a send, the few emails in flight at that moment can go out a second time when the broadcast resumes. After a crash, sending can pause for up to five minutes before another server picks it up.

Current limitations

  • No personalization. The subject and body are sent exactly as written, so placeholders such as {{user_name}} arrive as literal text.
  • No scheduling, saved campaigns or send history. Each broadcast is a one-off request. Only its job shows what happened, for 30 days, and there is no list of past jobs.
  • No open or click tracking.
  • Built-in segments only. You cannot define custom segments or filter on your own consent fields.

Consent is your responsibility

Only email users who expect to hear from you. OrbitNest handles unsubscribes from broadcasts, but laws such as CAN-SPAM and GDPR can require more, such as recording consent or including your postal address. Add anything else your audience needs to the body yourself.

For a single email to one recipient, use the Email API.