How-to
Schedule and cancel emails
Send an email later with scheduled_at, change the send time, or cancel a scheduled, accepted or retrying email from the API or the dashboard.
This page explains how to schedule an email for later with the Email API, how to move it to a different time, and how to cancel an email before it leaves. Canceling also works for emails that weren’t scheduled, as long as they haven’t been delivered yet.
Schedule an email
Add scheduled_at to a send request. The response has "status": "scheduled" and the normalized time in scheduled_at, and each recipient’s email emits email.scheduled instead of email.accepted.
scheduled_at accepts these formats:
| Format | Example | Notes |
|---|---|---|
| ISO 8601 with a time zone | 2026-10-05T09:00:00Z, 2026-10-05T09:00:00+02:00 |
Recommended. Always include Z or an offset. |
| Natural language | tomorrow at 9am, in 2 hours, next monday 10:00, friday 5pm |
Interpreted in UTC, so tomorrow at 9am means 09:00 UTC. |
A time that is now or in the past sends the email immediately with the status accepted.
curl https://api.emailit.com/v2/emails \
-H "Authorization: Bearer $EMAILIT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "Acme <reminders@acme.com>",
"to": "ada@example.com",
"subject": "Your appointment is tomorrow",
"text": "See you at 14:00.",
"scheduled_at": "2026-10-05T09:00:00Z"
}'const email = await emailit.emails.send({
from: 'Acme <reminders@acme.com>',
to: 'ada@example.com',
subject: 'Your appointment is tomorrow',
text: 'See you at 14:00.',
scheduled_at: '2026-10-05T09:00:00Z',
});email = client.emails.send({
"from": "Acme <reminders@acme.com>",
"to": "ada@example.com",
"subject": "Your appointment is tomorrow",
"text": "See you at 14:00.",
"scheduled_at": "2026-10-05T09:00:00Z",
})$email = $emailit->emails()->send([
'from' => 'Acme <reminders@acme.com>',
'to' => 'ada@example.com',
'subject' => 'Your appointment is tomorrow',
'text' => 'See you at 14:00.',
'scheduled_at' => '2026-10-05T09:00:00Z',
]);Emailit prepares a scheduled email when you make the request, not at the send time. The template is rendered, URL attachments are downloaded and credits are charged up front. To change the content, cancel the email and send a new one.
Change the send time
Use Update a scheduled email (POST /emails/{id}) with a new scheduled_at. The same formats are accepted.
- The email’s status must be
scheduled. - Its current send time must be more than 3 minutes away.
- The new send time must be more than 3 minutes in the future.
curl https://api.emailit.com/v2/emails/em_33VtK8mRq1xZp7LwN4cY2bHsDfa \
-H "Authorization: Bearer $EMAILIT_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "scheduled_at": "2026-10-05T15:00:00Z" }'await emailit.emails.update('em_33VtK8mRq1xZp7LwN4cY2bHsDfa', {
scheduled_at: '2026-10-05T15:00:00Z',
});client.emails.update("em_33VtK8mRq1xZp7LwN4cY2bHsDfa", {
"scheduled_at": "2026-10-05T15:00:00Z",
})$emailit->emails()->update('em_33VtK8mRq1xZp7LwN4cY2bHsDfa', [
'scheduled_at' => '2026-10-05T15:00:00Z',
]);{
"object": "email",
"id": "em_33VtK8mRq1xZp7LwN4cY2bHsDfa",
"status": "scheduled",
"scheduled_at": "2026-10-05T15:00:00.000Z",
"updated_at": "2026-10-01T10:02:44.193027Z",
"message": "Email schedule has been updated successfully"
}Unlike a new send, an unreadable time is rejected here with 422 Invalid scheduled_at. A request that breaks the 3-minute rule, or targets an email that isn’t scheduled, fails with 422 Cannot update email. A request with several recipients creates one email per recipient, so reschedule each em_ ID from the ids map. Rescheduling isn’t available in the dashboard.
Cancel an email
You can cancel an outgoing email while it has one of these statuses:
| Status | Can you cancel? | Notes |
|---|---|---|
scheduled |
Yes | Only while the send time is more than 3 minutes away. |
accepted |
Yes, best effort | The email is waiting in the send queue or about to leave it. |
attempted |
Yes, best effort | A delivery attempt failed temporarily. Canceling stops the remaining retries. |
| Any other status | No | Emails that were delivered, bounced, failed, rejected, suppressed, held, or already canceled can’t be canceled. |
- Go to Email APIEmails.
- Select Cancel delivery on the email’s row, or open the email and select Cancel delivery at the top of the page.
- Confirm. If a delivery attempt had already started, the dashboard warns you that the attempt may still complete and that the remaining retries were stopped.
Call Cancel an email (POST /emails/{id}/cancel). It works with Full Access and Sending Only keys.
curl -X POST https://api.emailit.com/v2/emails/em_33VtK8mRq1xZp7LwN4cY2bHsDfa/cancel \
-H "Authorization: Bearer $EMAILIT_API_KEY"{
"object": "email",
"id": "em_33VtK8mRq1xZp7LwN4cY2bHsDfa",
"status": "canceled",
"in_flight": false,
"message": "Email has been canceled and removed from the send queue."
}When in_flight is true, the email was canceled but a delivery attempt may already be underway, and the message reads “The current delivery attempt may still complete; remaining retries were stopped.” A status that can’t be canceled, or a scheduled email less than 3 minutes from its send time, returns 422 Cannot cancel email.
Canceling doesn’t refund the credits charged when the email was sent through the API.
How canceling works
Canceling pulls the email out of the send queue. It isn’t a recall from the recipient’s inbox.
- Emailit checks that the email can still be canceled.
- It sets the status to
canceled, adds a “Canceled” entry to the email’s delivery history and removes it from the send queue. - If a delivery worker has already picked the email up, the worker checks the status again right before handing the message to the recipient’s server and skips it when it sees
canceled. - Emailit emits
email.canceledwith theprevious_status.
If the message was already on its way to the recipient’s server, that attempt can still succeed. Emailit keeps the status canceled even if the racing attempt is delivered or bounces, but the recipient may still get the message. Treat canceling as “stop this before it leaves”, not “unsend”.
Statuses and events
| Moment | Status | Webhook event |
|---|---|---|
Request with a future scheduled_at |
scheduled |
email.scheduled |
| Send time arrives | delivered, attempted, bounced and so on |
The matching delivery event, such as email.delivered |
| Canceled | canceled |
email.canceled, with status and previous_status |
A scheduled email doesn’t emit email.accepted when its send time arrives. See Email statuses for the full list.