Skip to main content

Mailbox History Backfill Guide

This guide covers the mailbox history backfill API — a one-time import of a connected mailbox's historical emails, delivered to your webhook.

Provider support

Backfill is currently supported only for Google (Gmail) OAuth IMAP mailboxes. Outlook/Microsoft and generic IMAP are not supported yet. The mailer you target must be a connected Gmail OAuth IMAP account with a configured webhook.


Overview

When a mailbox is connected, the live poller only forwards mail that arrives after connection. Backfill imports the historical emails that predate (or surround) that point, so a newly connected mailbox can build a complete communication timeline.

How it works:

  • You start a backfill for a connected mailer. The platform walks the mailbox newest-first and delivers each email individually to the mailer's configured webhook (the same IMAP_OAUTH incoming-email webhook used by live mail).
  • Delivery is at-least-once: a slice may be retried (on transient errors, redelivery, or resume), so the same email can be delivered more than once. Your webhook must dedupe by Message-Id.
  • The job runs asynchronously; poll the status endpoint for progress, or abort it at any time.

Prerequisites

  1. A connected Gmail OAuth IMAP mailer (mailerID).
  2. A webhook configured on that mailer (backfilled emails are delivered there).
  3. A valid API token (the same auth used for other /v1 endpoints).

Endpoints

MethodPathPurpose
POST/v1/{mailerID}/backfillStart a backfill job
GET/v1/{mailerID}/backfill/{jobId}Get job status / progress
POST/v1/{mailerID}/backfill/{jobId}/abortCancel an in-flight job

See the API Reference → Backfill section for the full generated schema.


Start a backfill

POST /v1/{mailerID}/backfill

Provide at least one of window_start or count:

FieldTypeRequiredNotes
window_startstring (RFC3339)required unless count is givenOldest point to walk back to, e.g. 2025-01-01T00:00:00Z.
window_endstring (RFC3339)optionalNewest point. Defaults to now.
countintegeroptionalCap on number of emails (newest-first). 0/omitted = no cap; bounded only by the window. Clamped to a server maximum (default 1000).
foldersobjectoptionalInclude non-INBOX folders: { "sent": false, "spam": false, "trash": false }.

Modes:

  • Window mode — give window_start (and optionally window_end) to import everything in that range.
  • Count mode ("last N") — give just count to import the most recent N emails. window_end defaults to now; the walk is bounded by a generous lookback.
  • Both — a window that is also capped at count emails.
curl -X POST "https://<your-host>/v1/{mailerID}/backfill" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"window_start": "2025-01-01T00:00:00Z",
"count": 1000,
"folders": { "sent": true }
}'
{ "success": true, "jobId": "01JC3BBW8S9YGX2VNKG5MD7BTA" }

Idempotent per mailer: only one active backfill per mailer at a time. A second request while one is in flight returns 409 with the existing jobId:

{ "success": false, "error": "active backfill already exists", "jobId": "01JC3BBW8S9YGX2VNKG5MD7BTA" }

Check status

GET /v1/{mailerID}/backfill/{jobId}

{
"success": true,
"jobId": "01JC3BBW8S9YGX2VNKG5MD7BTA",
"status": "processing",
"processed": 250,
"target": 1000,
"percent": 25,
"startedAt": "2026-06-03T10:07:23Z",
"endedAt": ""
}
  • statuspendingprocessingdone (or failed / cancelled).
  • percent — time-based progress over the requested window (clamped 0–100; 100 when done).
  • processed / target — emails delivered so far / the count cap (0 = uncapped).
  • endedAt — set once the job reaches a terminal state.

Abort a backfill

POST /v1/{mailerID}/backfill/{jobId}/abort

Cancels an in-flight job; the worker stops cleanly at its next slice, leaving the job cancelled. Already-finished jobs (done/failed/cancelled) return 409.

{ "success": true, "jobId": "01JC3BBW8S9YGX2VNKG5MD7BTA", "status": "cancelled" }

After a job is cancelled (or finished), you can start a new backfill for the same mailer.


Webhook delivery & dedupe

  • Each historical email is delivered as a normal incoming-email webhook (IMAP_OAUTH), with the full email content inline.
  • Backfill deliveries carry an X-Backfill-Job-Id header so you can distinguish them from live mail.
  • Because delivery is at-least-once, dedupe by Message-Id on your side — this is required, not optional.

Notes & limits

  • Gmail only (for now): see the provider-support note above.
  • Throughput is bounded by Gmail's per-user API quota (~3,000 messages/min) and by your webhook endpoint's speed; large mailboxes take minutes. Use the status endpoint to track progress.
  • Window precision is rounded to whole seconds (Gmail's date filter is day-granular).