Skip to content

Import Existing Mail & Lists

Choose the right local-first path for Gmail, password-authenticated IMAP, mbox, Mailchimp, or a Tinbox account archive.

Move old mail and subscriber lists into Tinbox with the tinbox import commands. The defining property is that the source fetch runs locally, on your machine. The source credentials never touch your deployment; its worker receives only the already-fetched batches to insert.

Tinbox account archives are different. They restore Tinbox rows and R2 objects without re-parsing them, through Settings → Export / Import. Use that path for a Tinbox-to-Tinbox move and the connectors below for a foreign source.

Local-first, credentials stay put

Each connector fetches on your laptop, then POSTs already-fetched batches to your deployment's source-agnostic bulk-insert API. There is no long-running worker job and no server-side credential storage. Your Gmail OAuth token, IMAP app password, or Mailchimp API key never leaves your machine.

The bulk-insert API is gated on a distinct import capability. A write scope by itself is not enough, and a token cannot grant the capability to itself. Have an organization admin create an agent/write token and grant import to that token principal through the deployment's administrative surface:

tinbox tokens create --inbox support --role agent --ttl 1d --json

Keep the returned plaintext token local and short-lived where practical. Use tinbox whoami --json to confirm that the token is valid and the target inbox is visible. The import capability is enforced when the first batch reaches the deployment; it is not implied by a successful whoami. See tinbox tokens create.

Choose by source

Source or use caseUseCurrent boundary
Gmail with local OAuth credentialstinbox import gmailRequires a client id, client secret, and refresh token already obtained through Google's installed-app OAuth flow
Any provider that offers a .mbox exporttinbox import mboxNo source authentication; best fallback for Google Takeout, desktop clients, and OAuth-only sources
Generic IMAP with a password or app passwordtinbox import imapOne mailbox/folder per run, TLS on port 993 by default
IMAP that requires OAuth/XOAUTH2Export to .mbox, then importThe current IMAP connector does not accept an OAuth access token
Outlook .pst fileExport or convert to .mbox, then importTinbox does not parse PST files directly
Mailchimp audiences and historical campaignstinbox import mailchimpCampaigns arrive archived and non-sendable
Another Tinbox deploymentSettings → Export / ImportRow-preserving account restore; do not feed the tar to tinbox import mbox

Imports are idempotent

Every import is re-runnable. The server dedupes on Message-ID (mail), email address (members), and source reference (campaigns), so a dropped batch re-POSTs safely and a second run of the whole import is not a duplicate. The output reports inserted new, deduped already present, and failed counts, so you can re-run until a flaky connection finishes the job.

mbox (zero auth)

This is the simplest and most portable path. Point it at a .mbox export from Google Takeout or a mail client. No source credentials are required.

tinbox import mbox ./takeout.mbox --inbox ibx_support --limit 100 --json

Use --limit for a trial run. Then re-run without it; Message-ID deduplication makes the overlap safe. Use --folder sent for a separate sent-mail export or another supported folder name for a file whose contents all belong together. See tinbox import mbox.

Gmail

Imports a Gmail mailbox over the Gmail API in RAW format, using your own local OAuth credentials. The CLI consumes a client id, client secret, and refresh token that you obtained locally; it does not launch the browser consent flow. Prefer environment variables so secrets do not enter shell history:

export GMAIL_CLIENT_ID=...
export GMAIL_CLIENT_SECRET=...
export GMAIL_REFRESH_TOKEN=...
tinbox import gmail --inbox ibx_support --query "older_than:1y" --limit 100 --json

Use Google's installed-app OAuth flow with the read-only Gmail scope to obtain the refresh token. --query scopes the import with a Gmail search; omit it for all mail. Remove the variables from the shell after the import. See tinbox import gmail.

IMAP

Imports one IMAP mailbox with a local client, using a password or app password. The connector always uses TLS and defaults to port 993.

export IMAP_PASSWORD=...
tinbox import imap --inbox ibx_support --host imap.example.com \
  --user you@example.com --mailbox INBOX --limit 100 --json

--mailbox picks the source folder. Run the command separately for every folder you want to bring over; a mailbox whose name contains sent maps to Tinbox's sent folder and other names currently map to inbox. The password comes from --password or IMAP_PASSWORD.

The current connector does not implement IMAP OAuth/XOAUTH2. If a provider does not permit password or app-password authentication, export the account to .mbox and use the zero-auth path instead. See tinbox import imap.

Mailchimp

Imports Mailchimp audiences (members, merge fields, tags) into a Tinbox audience, and optionally your past campaigns.

export MAILCHIMP_API_KEY=...
tinbox import mailchimp --campaigns --json

--list-id imports a single audience; --audience-id merges into an existing Tinbox audience instead of creating one. With --campaigns, past campaigns come in as archived, non-sendable rows: they are a historical record, not something you can accidentally re-send. See tinbox import mailchimp.

In the app (no CLI)

For subscriber lists you can import contacts straight from the inbox — no terminal needed. Go to Lists → Import and pick a source:

  • CSV file — bring any contact list (a Resend or Constant Contact export, Google Contacts, a spreadsheet). Upload the file and we auto-detect which column is the email, which is the name, and propose every other column as a merge field. Review the mapping, fix anything we guessed wrong, choose whether to update or skip contacts that already exist, then import. Each batch POSTs to the same idempotent bulk-insert API, so re-importing the same list updates members instead of duplicating them.
  • Mailchimp — upload a Mailchimp audience export (Audience → All contacts → Export Audience); status, tags, merge fields, and the member rating (→ VIP) map automatically.

Both land the contacts as a new audience you review before sending. The in-app path runs entirely in your browser against your own deployment — for the live-API Mailchimp pull (audiences and past campaigns) or for mail history, use the CLI connectors above.

Run a migration safely

  1. Import into a non-production or newly created inbox first when possible.
  2. Start with --limit 100 for Gmail, IMAP, or mbox and inspect several threads, dates, sent/inbox placement, raw source, and attachments.
  3. Run the complete import. If the local process or network stops, re-run the same command; the server converges on Message-ID instead of duplicating mail.
  4. Review the reported inserted, deduped, and failed counts. A non-zero failure count warrants another run or a narrower source query.
  5. Remove local credential variables and revoke the temporary Tinbox token when the migration is complete.

Imported mail is stored through the same ingest path as live inbound mail: raw source is retained, MIME is parsed, and allowed attachment bytes go to object storage. Dangerous attachment types can still be blocked by the deployment's security policy.

Next steps