Skip to content
Sendora Cloud
Create account
Engage

Email

Transactional + broadcast email with provider-isolated reputation, BYOD (bring your own domain), inbound routing, and reply threading.

Features

  • **BYOD (bring your own domain)** — one-time DNS setup, real Resend Domains integration (POST /domains + verify), DKIM signed by you, reputation isolation per tenant.
  • **4-mode category routing** — transactional / auth / inbound_ack / ticket → Cloudflare provider; broadcast / workflow → Resend. Platform-critical mail isolated from customer broadcasts.
  • **Consent enforcement (Wave 1a)** — opt-in `enforce_consent` toggle on org settings. When on, broadcast + workflow categories require a granted `marketing` consent row for `input.to` before dispatch. No record OR revoked → `email_sends` row with `status='failed' provider='suppressed' suppressed_reason='no_consent'` for audit.
  • **RFC 8058 one-click unsubscribe** + per-org suppression list. **Honest:** suppressions are scoped `(org_id, email)` — per-org, not platform-wide. An unsubscribe on one Sendora-using org does NOT propagate to another.
  • **Content safety scanner** blocks phishing / credential-harvest patterns on customer-authored mail (broadcast / workflow / transactional). Platform categories (ticket / auth / inbound_ack) bypass.
  • **Recipient-dedup at dispatch** — `(orgId, recipient, subject)` within 60s suppressed. Belt-and-braces below device-takeover.
  • **Per-org rate limits + 30-day probation pool** for new senders — reputation isolation between tenants.
  • **Signed bounce + complaint webhooks** — Resend Svix-HMAC + SES SNS + CF synchronous + CF GraphQL bounce poller every 15m → `email_suppressions`.
  • **Templates with `{{var}}` interpolation + sandbox preview** — **honest:** the renderer is regex `{{var}}` replace, NOT Liquid. No `{% if %}`, no helpers — single-variable substitution only.
  • **`email.*` events** — `email.sent`, `email.delivered`, `email.opened`, `email.clicked`, `email.bounced`, `email.complained` fire on the platform bus. Webhooks subscription captures every state change.
  • **Audience fan-out via Automation** — pick an audience in a workflow trigger, `send_email` step fires per matched user. **Honest:** there's no single-call `sendToAudience()` API; the fan-out is the workflow.

Common use cases

  • BYOD transactional + lifecycle email where the same tenant holds your Customers + Automation + Audit.
  • Product-led growth lifecycle (welcome / activation / re-engage) triggered automatically by Analytics events.
  • Multi-tenant SaaS routing mail per customer's own domain with reputation isolation per tenant.

Key concepts

BYOD
Customer-authored outbound ships from the customer's own verified domain. Keeps Sendora's SES reputation isolated from customer content.
Reputation isolation
Auth/transactional → Cloudflare Email Service. Workflow/broadcast → Resend. Customer complaints on broadcast can't tank password resets.
Inbound routing
CF Email Routing forwards `*@yourdomain` into Sendora's email-worker → dual-path: Gmail forward + Sendora ticket.

Setup

  1. 1
    Verify domain (BYOD)
    Dashboard → Settings → Email. Add DNS DKIM + SPF + DMARC records. Verification polls Resend.
  2. 2
    Optional inbound
    Add CF Email Routing rule pointing `support@yourdomain` → Sendora email-worker.

Send + receive

Send transactional email

FREE

Server-side send (sk_* secret key). Per-org rate-limited (60/min default, 10/min on probation). BYOD required for production volume; shared default for first 50/day. Returns sendId for tracking.

curl -X POST https://api.sendoracloud.com/api/v1/orgs/<ORG_UUID>/email/send \
  -H "x-api-key: pk_prod_…" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "alice@example.com",
    "subject": "Welcome",
    "category": "transactional",
    "html": "<p>Welcome to Acme</p>"
  }'

Send a templated email

FREE

Reference a saved template by id with mustache-style variable substitution. Templates manage in dashboard or via /email/templates CRUD.

curl -X POST https://api.sendoracloud.com/api/v1/orgs/<ORG_UUID>/email/send \
  -H "x-api-key: pk_prod_…" \
  -d '{ "to": "alice@example.com", "templateId": "<TEMPLATE_UUID>", "variables": { "firstName": "Alice" } }'

Templates CRUD

FREE

Create / list / get / update / delete saved templates. Subject + html + text + category. Use templateId on send.

# Create
curl -X POST https://api.sendoracloud.com/api/v1/orgs/<ORG_UUID>/email/templates \
  -H "x-api-key: pk_prod_…" \
  -d '{ "name": "welcome", "subject": "Welcome {{firstName}}", "html": "<p>Hi {{firstName}}</p>", "category": "transactional" }'

# List
curl https://api.sendoracloud.com/api/v1/orgs/<ORG_UUID>/email/templates -H "x-api-key: pk_prod_…"

# Preview render
curl -X POST https://api.sendoracloud.com/api/v1/orgs/<ORG_UUID>/email/templates/<TEMPLATE_UUID>/preview \
  -H "x-api-key: pk_prod_…" \
  -d '{ "variables": { "firstName": "Alice" } }'

Bring your own domain (BYOD)

FREE

Add custom sending domain in Dashboard → Email → Custom domains. Returns DKIM + SPF + DMARC records to add to DNS. Real Resend-backed verification. Required before sending from your own domain.

# BYOD setup is dashboard-only — visual editor for DNS records + verification status.
# Once verified, sends use the BYOD From address automatically.

Query send history

FREE

List recent sends + per-send detail. Filter by status / recipient / category. Status enum: queued | sent | delivered | bounced | complained | failed | suppressed.

# List
curl 'https://api.sendoracloud.com/api/v1/orgs/<ORG_UUID>/email/sends?status=bounced&pageSize=20' \
  -H "x-api-key: pk_prod_…"

# Aggregate stats (delivery rate / open rate / click rate)
curl https://api.sendoracloud.com/api/v1/orgs/<ORG_UUID>/email/sends/stats \
  -H "x-api-key: pk_prod_…"

# Reputation (bounce + complaint thresholds + probation status)
curl https://api.sendoracloud.com/api/v1/orgs/<ORG_UUID>/email/reputation \
  -H "x-api-key: pk_prod_…"

Inbound email + threading

STARTER+

Cloudflare Email Routing forwards your domain's mail to Sendora. Replies threaded into originating Support ticket via plus-addressing (`+T<ticketId>`). Webhooks at `/email/webhooks/ses` + `/email/webhooks/resend` for provider receipts.

# Configure inbound in dashboard → Email → Inbound. No SDK call needed.
# Test by replying to a ticket-originated email — reply lands as a new ticket comment.

One-click unsubscribe (RFC 8058)

FREE

Sendora auto-stamps List-Unsubscribe + List-Unsubscribe-Post headers + appends footer link. POST `/unsubscribe/:token` applies suppression — handled by Sendora; your app does nothing.

# Both endpoints are public + token-scoped; the SDK never calls them.
# Token is signed; tampering returns 400.
curl https://api.sendoracloud.com/api/v1/unsubscribe/<TOKEN>          # GET → confirmation page
curl -X POST https://api.sendoracloud.com/api/v1/unsubscribe/<TOKEN>  # applies suppression

Delivery + bounce webhooks

FREE

Subscribe to email.delivered / email.bounced / email.complained / email.opened / email.clicked. Signed via HMAC-SHA256 in `X-Sendora-Signature` header.

curl -X POST https://api.sendoracloud.com/api/v1/orgs/<ORG_UUID>/webhooks/endpoints \
  -H "x-api-key: pk_prod_…" \
  -d '{
    "url": "https://your-app.com/hooks/sendora",
    "events": ["email.delivered","email.bounced","email.complained","email.opened","email.clicked"]
  }'

Related