Transactional email in one API call
One POST sends a message. The response is an ID, and everything that happens to the email afterwards is recorded against it.
import { Rasket } from "rasket";
const rasket = new Rasket({ apiKey: process.env.RASKET_API_KEY });
const { body: email } = await rasket.emails.send( { from: "Acme <orders@send.acme.example>", to: ["ronald.williams@example.com"], subject: "Your order has shipped", html: "<p>Order 1042 shipped today.</p>", }, { idempotencyKey: "order-1042" },);
console.log(email.id);What one send request gives you
The hard parts of a transactional send are in the request itself, not in a library you have to write around it.
Idempotent retries
Put an Idempotency-Key on a send and repeat it as often as you like. For 24 hours the same key and payload return the first response instead of a second email, and a different payload under that key is refused rather than sent.
Batches of up to a hundred
One request carries up to a hundred messages, each shaped like a single send. They are validated all or none, written in one transaction, and the IDs come back in the order you sent them.
Scheduled sends you can move
Set scheduled_at to an ISO 8601 time between one minute and thirty days from now. While the message is waiting you can move it to a new time or cancel it.
Attachments, by value or by URL
Up to a hundred per message. Each one is a filename plus either base64 content or an https link we fetch for you, with an optional content type and content ID for inline images.
Templates by ID or alias
A send can name a published template instead of carrying a body, and the values it passes are filled in. The email records which version it used.
The full field list, the limits and the error vocabulary are on the emails reference. Templates have a page of their own.
How a send travels from your request to the inbox
Three stages, in the same order for every message, whether it came from your code, from a schedule or from the dashboard.
- 1
You post one message
It is authenticated, validated against the same schemas the API reference is generated from, checked against your suppression list and your quota, then written down in one transaction. A 200 with an ID means we have taken responsibility for it.
- 2
A durable run sends it
The job is picked up and submitted to the mail infrastructure. A scheduled send sleeps until its time and then does exactly the same thing, so there is no second path with weaker checks.
- 3
Events say what happened
Every step is recorded against the email and posted to your webhook endpoints. Sent, delivered, bounced, complained and failed arrive the same way, and so do opens and clicks once tracking is on for the domain.
The sender address has to be on a domain your team has verified, and an unverified one is refused rather than quietly dropped. Adding one is covered on the domains page, and the five steps to a first delivered message are in the quickstart.
The delivery timeline every email keeps
Every message keeps a record of what happened to it, and you can read it back at any time.
An email's last event is the furthest state it has reached: queued, scheduled, sent, delivery_delayed, delivered, opened, clicked, bounced, complained, failed, suppressed or canceled. The timeline behind it lists each event with its recipient and the moment it happened, in the order they happened rather than the order they reached us.
GET /emails/{email_id}/events
{ "object": "list", "has_more": false, "data": [ { "object": "email_event", "id": "0199d2f1-4c4e-7a20-9c31-6f2b8a0e5f01", "type": "email.delivered", "recipient": "ronald.williams@example.com", "occurred_at": "2026-09-09T09:20:33.412Z", "data": {} } ]}For more than a spot check, subscribe an endpoint instead of polling. Every event is posted to your webhooks with a signature and a timestamp, and each payload is listed on the events page.
Typed clients, request logs and rate limit headers
The API is plain HTTPS, and the parts that are tedious to write twice are already written.
The Node and Python clients have their request and response types generated from the same document the API is validated against, so they cannot drift from it. Both hand back the rate limit, the request ID and whether a keyed call was replayed alongside the body, and both retry a send that carries an idempotency key while never retrying one without a key.
The limit is ten requests a second per team, shared across every key the team holds. Three headers ride on every response and a fourth appears when you are refused, so a client can slow down before it is turned away. A batch counts as one request rather than a hundred, which is usually the fix for a throttled loop. The details are on the rate limits page.
Every call made with your team's credentials is kept in a request log with its status, its latency and the request ID quoted in any error, so a send that went wrong is diagnosed from the record. Stored bodies are measurements, not your message.
Questions about the email API
How do I stop a retry from sending the same email twice?
Send an Idempotency-Key header on POST /emails or POST /emails/batch, and reuse the same string for every retry of the same work. For 24 hours a repeat returns the first response instead of sending again, and a different payload under a key you have already used is refused rather than sent.
Does a 200 mean the email was delivered?
No. A 200 with an ID means we have durably recorded the message and taken responsibility for sending it. Delivery is reported later, as an event on the email and on your webhook endpoints, usually within seconds.
How many emails can I send in one request?
Up to a hundred. POST /emails/batch takes an array of send objects shaped exactly like a single send, validates them all or none while naming the index that failed, and counts as one request against your rate limit.
Can I schedule an email and change my mind?
Yes. scheduled_at takes an ISO 8601 time between one minute and thirty days from now, and natural language such as in 1 min is rejected rather than guessed at. While the message is waiting you can move it to a new time or cancel it; once it has been dispatched the API says so instead.
How do I attach a file to an email?
Each attachment carries a filename and exactly one of base64 content or an https URL we fetch. A message may carry up to a hundred, with a content type and a content ID where an inline image needs one.
What happens if I send to an address that has bounced?
Nothing goes out to it. A permanent bounce or a spam complaint puts the address on your team's suppression list, and a later send to it is skipped and recorded as suppressed. The request still answers 200 with an ID, so your code needs no special case.
Make your first send
Sign up, verify a domain and post one message. The response is an ID you can follow.