Recover missed events
Replay missed provider events through your existing hooks with sync().
Server was down? Webhook never arrived? sync() asks the provider for the events from that window and runs them through your existing hooks, oldest first. No separate recovery code path — the same hooks handle live and replayed events.
const result = await emailkit.sync({
emailDriver: "resend",
since: outageStartedAt,
});const result = await emailkit.domains.sync({
emailDriver: "mailgun",
domain: "mg.example.com",
since: outageStartedAt,
});const result = await emailkit.mailboxes.sync({
emailDriver: "outlook",
mailbox,
auth,
since: outageStartedAt,
});The result tells you how many events were replayed and syncedFrom — how far back the provider could actually look. Pass until to limit the range and signal to cancel a long sync.
Replays are safe by design
Sync can deliver events your app already saw. The same rules that make webhooks safe make sync safe:
- Save received mail by
messageIdso an existing message updates instead of duplicating. - Ignore repeated
eventIdvalues when present. - Pass a
contextflag to skip side effects you don’t want during recovery, like auto-replies:
await emailkit.sync({
emailDriver: "aiinbx",
since,
context: { replay: true },
});
Continue after a failure
If one of your hooks throws mid-sync, emailkit tells you where to pick up:
import { EmailKitSyncError } from "emailkit";
try {
await emailkit.sync({ emailDriver: "resend", since });
} catch (error) {
if (error instanceof EmailKitSyncError) {
await emailkit.sync({
emailDriver: "resend",
since: error.lastEventTimestamp ?? since,
});
}
}
What each provider can replay
| Provider | Scope | Recoverable history |
|---|---|---|
| Resend | Account | Inbound email |
| AIInbx | Account | Inbound email |
| Mailgun | Account or domain | Inbound and tracking events within retention |
| Gmail | Mailbox | Inbound mailbox history |
| Outlook | Mailbox | Received mailbox messages |
