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 case | Use | Current boundary |
|---|---|---|
| Gmail with local OAuth credentials | tinbox import gmail | Requires a client id, client secret, and refresh token already obtained through Google's installed-app OAuth flow |
Any provider that offers a .mbox export | tinbox import mbox | No source authentication; best fallback for Google Takeout, desktop clients, and OAuth-only sources |
| Generic IMAP with a password or app password | tinbox import imap | One mailbox/folder per run, TLS on port 993 by default |
| IMAP that requires OAuth/XOAUTH2 | Export to .mbox, then import | The current IMAP connector does not accept an OAuth access token |
Outlook .pst file | Export or convert to .mbox, then import | Tinbox does not parse PST files directly |
| Mailchimp audiences and historical campaigns | tinbox import mailchimp | Campaigns arrive archived and non-sendable |
| Another Tinbox deployment | Settings → Export / Import | Row-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
- Import into a non-production or newly created inbox first when possible.
- Start with
--limit 100for Gmail, IMAP, or mbox and inspect several threads, dates, sent/inbox placement, raw source, and attachments. - 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.
- Review the reported
inserted,deduped, andfailedcounts. A non-zero failure count warrants another run or a narrower source query. - 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
- Send a newsletter to the audience you just imported.
- Read the core concepts behind audiences, contacts, and members.
- Retrieve mail and attachments after the import.
- Download all your Tinbox data for a Tinbox-to-Tinbox move rather than a foreign-source import.