Scheduled reminder in the recipient's timezone
You know the recipient's IANA timezone (e.g. America/New_York) and you want "tomorrow at 9 AM their time".
Client-side — compute UTC
import { Temporal } from "@js-temporal/polyfill";
function nextNineAmInTz(tz: string): string {
const now = Temporal.Now.zonedDateTimeISO(tz);
const target = now
.with({ hour: 9, minute: 0, second: 0, millisecond: 0 })
.add({ days: now.hour < 9 ? 0 : 1 });
return target.toInstant().toString(); // ISO 8601 UTC
}
const scheduled_at = nextNineAmInTz("America/New_York");
Send
await mr.emails.send({
from: "reminders@yourdomain.com",
to: ["recipient@example.com"],
subject: "Your reminder",
html: "<p>Here it is.</p>",
scheduled_at, // "2026-04-23T13:00:00.000Z" (9 AM ET in April)
});
Response:
{
"id": "msg_01HN...",
"status": "scheduled",
"scheduled_at": "2026-04-23T13:00:00.000Z"
}
Cancel if plans change
curl -X DELETE https://api.sendoka.com/api/v1/emails/msg_01HN... \
-H "Authorization: Bearer $SENDOKA_API_KEY"
Returns 409 NOT_SCHEDULED if the cron already picked it up.
Use native recipient-timezone scheduling
If you don't want to compute UTC yourself, use the send_at_local form:
{
"from": "reminders@yourdomain.com",
"to": ["recipient@example.com"],
"subject": "Your reminder",
"html": "<p>Here it is.</p>",
"send_at_local": "09:00",
"recipient_timezone": "America/New_York"
}
Sendoka computes the next occurrence of 09:00 in the given tz and stores scheduled_at accordingly. See api/timezone-schedules.md.
Gotchas
- DST transitions —
Temporalhandles these; naiveDatemath doesn't. Use it. - Minute granularity — the cron runs once per minute. A message scheduled for 09:00:45 fires at the 09:01 tick.
- Past times — Sendoka treats
scheduled_atwithin the next 1 second as immediate (not scheduled). Far past is rejected withVALIDATION_ERROR.