---
title: "Schedule and cancel"
description: "Send later, move it, or stop it."
url: "https://openemail.uk/docs/api/emails/schedule"
area: "API"
category: "Emails"
---

# Schedule and cancel

Send later, move it, or stop it.

**Also documents:** `PATCH /emails/{id}`, `POST /emails/{id}/cancel`

## Scheduling

`scheduledAt` takes an ISO-8601 instant or a duration like `PT2H`, up to a year out. A scheduled message answers `202` with `status: "scheduled"` and stays cancellable right up until it sends.

`cancellableForSeconds` does the same for an immediate send: the composer's undo-send window, exposed rather than hardcoded to a user setting that has no business deciding an API's behaviour. The two are mutually exclusive: a scheduled message is already cancellable.

## Schedule a send

Two hours out. The response carries the id you will need to move or stop it.

**curl**

```
curl -X POST "$OE/emails" -H "$AUTH" -H "Content-Type: application/json" \
    -d '{
      "from": "billing@acme.com",
      "to": ["ada@example.com"],
      "subject": "Your September invoice",
      "html": "<p>Invoice attached.</p>",
      "scheduledAt": "PT2H"
    }'
```

**Response**

```
HTTP/1.1 202 Accepted
  Location: /emails/msg_8cd0a316930b4482a8b8440b

  {
    "object": "email",
    "id": "msg_8cd0a316930b4482a8b8440b",
    "status": "scheduled",
    "scheduledAt": "2026-09-01T10:19:41.345Z",
    "cancellableUntil": "2026-09-01T10:19:41.345Z",
    "messageId": null,
    "transport": null,
    "sentAt": null
  }
```

> `202`, not `200`: something still has to happen to it. An immediate send answers `200` with `status: "sent"`, so a caller can branch on the status code alone.

## Move it

`PATCH /emails/{id}`. Only `scheduledAt` can change, and only while it is queued or scheduled.

**curl**

```
curl -X PATCH "$OE/emails/msg_8cd0a316930b4482a8b8440b" \
    -H "$AUTH" -H "Content-Type: application/json" \
    -d '{ "scheduledAt": "PT6H" }'
```

**Response**

```
{
    "object": "email",
    "id": "msg_8cd0a316930b4482a8b8440b",
    "status": "scheduled",
    "scheduledAt": "2026-09-01T14:20:15.881Z"
  }
```

## Stop it

`POST /emails/{id}/cancel`.

**curl**

```
curl -X POST "$OE/emails/msg_8cd0a316930b4482a8b8440b/cancel" -H "$AUTH"
```

**Response**

```
{ "object": "email", "id": "msg_8cd0a316930b4482a8b8440b", "status": "cancelled" }
```

> Cancelling twice is not an error. The second call returns the same cancelled message, so a retry is safe.

> Cancelling one that has already gone is a `409 email_not_cancellable`. It cannot be un-sent, and answering anything else would be a lie.
