Skip to main content
POST /send-email Queues an email for immediate sending or schedules it for a future date.
Advanced API (recipient/sender/html) — the only one with scheduled sending, templates, and dry_run. For simple integrations, the v1 API uses REST-style names and a stable contract.

Authentication

Bearer token with a project API key:
sk_proj_*/sk_live_* (Live) and sk_test_* (Test) are accepted. The project_id is inferred from the key. Learn more in Authentication.

Request Body

Attachments

Each object in the attachments array has the following structure: Limits:
  • Maximum 10 attachments per email.
  • Maximum 10 MB per individual attachment.
  • Maximum 10 MB total per email (sending-infrastructure limit).
Attachments are processed in the background: if one exceeds the limits or its URL is not accessible, the send fails asynchronously and is recorded in the activity record. Learn more in Attachments.

Scheduled Sending

The scheduled_at field supports multiple formats:

ISO 8601 timestamp

Natural language (English)

Time zone (timezone)

The timezone field is used to interpret scheduled_at correctly. It supports:
  • IANA name: "America/Santiago", "US/Eastern", "Europe/Madrid"
  • Offset: "+09:00", "-05:00", "UTC-3", "GMT+9"
  • Integer number: -3, 9 (no fractions — for half-hour zones like India, use the "+05:30" format)
If no timezone is provided, the project’s default time zone (default_timezone) is used. If the project has no time zone configured, UTC is assumed. Learn more in Schedule Sends.

Manage a Scheduled Send

A POST /send-email with scheduled_at returns a scheduled_send_id (see the scheduled send response). With that ID you can inspect, reschedule, or cancel the send while it is still in pending status.

GET /v1/scheduled-sends/:id

Returns the status of the scheduled send.
Response 200 OK
Responds 404 NOT_FOUND if the ID does not exist in the project.

PATCH /v1/scheduled-sends/:id

Reschedules the send to a new date. Only while the status is pending.
Response 200 OK — the updated row, with the same columns as the GET.

DELETE /v1/scheduled-sends/:id

Cancels the send if it is still pending.
Response 200 OK

Dry Run

With "dry_run": true, the endpoint renders the email without sending it: it does not queue, log activity, or consume quota. Useful for validating the payload and variables before an actual send.
html_preview is truncated to 8000 characters. Variables with no value in data are left as {{variable}} in the preview.

Headers

Learn more about Idempotency-Key in API Keys.

Request Example

Immediate send

Response 200 OK

Scheduled send with attachments

Response 200 OK
Learn more in Node.js SDK.

Immediate Send Response

Sending is asynchronous: the endpoint queues the email and responds immediately with 200 (see the example above). The actual send happens in the background. The final send result (delivered, bounced, failed) does not come in this response: it is queried via the Activity API using email_id, or received via webhooks (email.send, email.delivery, email.bounce, etc.).

Send Type

The email_type field declares the nature of the send, and that determines which suppressions apply to it.
If you send marketing, declare email_type: "marketing" explicitly. An unsubscribe is consent: only sends declared as marketing honour it. Without the field your send is treated as transactional and would reach people who asked not to receive your campaigns.
Why the default is transactional: a bounce is a signal from the mailbox (that address does not exist) and must block everything, but a newsletter unsubscribe is a signal from the user about your campaigns — it cannot stop them from receiving their verification code or the result they asked for.
The values campaign and automation are treated as marketing. Any other value (individual, welcome, …) is accepted for backwards compatibility and counts as transactional.

Suppressed Recipient

If the recipient is on the project’s suppression list, the email is not queued: the API responds 200 immediately with suppressed: true, and nothing goes out to the recipient. Which suppressions apply depends on the send type: a transactional send is only blocked by a hard bounce or complaint; a marketing send is also blocked by voluntary unsubscribes.
This is an intentional 200 (not an error): retrying the same send returns the same result. The right thing to do is to flag the address in your system and stop sending to it — you can also listen to the email.suppressed webhook to sync it automatically. The list is managed in the dashboard (Audience → Suppressed).

Automatic Reply-To (Inbound Email)

All sends via the API automatically include a Reply-To header with the sender’s name:
Clients display the sender’s name, not the technical address. When the recipient replies, the reply arrives at RQE and triggers an email.inbound webhook with attachments. See Webhooks → Inbound.

Sender Verification

The sender must be verified before you can send. There are two ways:
  1. Verify the individual email via magic link (POST /domains/verify-email).
  2. Verify the entire domain via DNS (POST /domains/register) — recommended, improves deliverability and lets you send from any address on the domain.
Verification is not synchronous: an unverified sender still receives 200 with queued: true, and the rejection happens in the background. The failure is recorded in the activity record (current_status: "failed", error_message), queryable via Activity with the email_id. Learn more in Domains API.

Error Codes

Since sending is asynchronous, the only synchronous errors (in the HTTP response) are validation errors: Send errors (unverified sender, invalid attachment, rate limit) occur in the background: the activity record moves to current_status: "failed" with the detail in error_message.

Error example