API Migrations
Import email from any IMAP provider via the REST API or MCP server.
Article details
Type, difficulty, plans, and last updated info.
▼
Article details
Type, difficulty, plans, and last updated info.
- Type
- Reference
- Difficulty
- Intermediate
- Plans
- Starter · Pro · Agency
- Last updated
- Apr 25, 2026
The Migration API lets you import email from any IMAP provider into a TrekMail mailbox — programmatically. You can test connections, start imports, monitor per-folder progress, cancel running jobs, retry failures, and clean up old records.
Before you start
- You need a Starter plan or higher. The Nano plan does not include the migration tool.
- All paid plans (Starter, Pro, Agency) get full access (
migrations:read+migrations:write) to start and manage migrations. - One migration can run per account at a time. Start a new one after the current one finishes or cancel it first.
Scopes
| Scope | What it does | Plans |
|---|---|---|
migrations:read |
List migrations, view migration details | Starter · Pro · Agency |
migrations:write |
Test connections, start, cancel, retry, delete | Starter · Pro · Agency |
Endpoints
Test connection
POST /api/v1/migrations/test-connection
Scope: migrations:write
Validates IMAP credentials and returns a list of source folders with message counts. Use this before starting a migration to verify the connection works and let the user choose which folders to import.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
source_host |
string | Yes | IMAP server hostname (e.g., imap.gmail.com) |
source_port |
integer | Yes | IMAP port (typically 993 for SSL) |
source_security |
string | Yes | ssl, tls, or none |
source_email |
string | Yes | Email address on the source server |
source_username |
string | No | Username if different from email |
source_password |
string | Yes | Password or app password |
Response (success):
{
"success": true,
"folders": {
"INBOX": 1234,
"Sent": 567,
"Drafts": 12,
"Work": 89
}
}
Response (failure): 422 with connection_failed error code.
List migrations
GET /api/v1/migrations
Scope: migrations:read
Returns a paginated list of migration jobs for your account.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter by status (pending, validating, planning, processing, completed, failed, cancelled) |
mailbox_id |
integer | Filter by target mailbox |
per_page |
integer | Results per page (default: 20, max: 100) |
Get migration
GET /api/v1/migrations/{id}
Scope: migrations:read
Returns detailed migration status including per-folder progress breakdown.
Response:
{
"data": {
"id": 5,
"mailbox_id": 10,
"mailbox_email": "support@acme.com",
"provider": "gmail",
"source_host": "imap.gmail.com",
"source_email": "j***e@gmail.com",
"status": "processing",
"progress": 45,
"total_messages": 1234,
"imported_messages": 556,
"failed_messages": 2,
"skipped_duplicates": 12,
"selected_folders": ["INBOX", "Sent"],
"import_since": "2025-01-01",
"skip_duplicates": true,
"folders": [
{ "name": "INBOX", "status": "processing", "expected": 1000, "imported": 450, "failed": 2, "skipped": 10 },
{ "name": "Sent", "status": "pending", "expected": 234, "imported": 0, "failed": 0, "skipped": 0 }
],
"error_message": null,
"poll_hint_seconds": 10,
"started_at": "2026-03-13T10:00:00+00:00",
"finished_at": null,
"created_at": "2026-03-13T09:59:50+00:00"
}
}
poll_hint_seconds tells you how often to poll for updates: 5 seconds during pending/validating/planning, 10 seconds during processing, null for terminal states.
source_email is masked for security (e.g., j***e@gmail.com).
Start migration
POST /api/v1/migrations
Scope: migrations:write
Starts a new email migration. Only one migration can run per account at a time.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
mailbox_id |
integer | Yes | Target TrekMail mailbox ID |
provider |
string | Yes | gmail, outlook, yahoo, icloud, or generic_imap |
source_host |
string | Yes | IMAP server hostname |
source_port |
integer | Yes | IMAP port |
source_security |
string | Yes | ssl, tls, or none |
source_email |
string | Yes | Source email address |
source_username |
string | No | Username if different from email |
source_password |
string | Yes | Source password or app password |
target_password |
string | Yes | Password for the target TrekMail mailbox |
selected_folders |
string[] | No | Specific folders to import (default: all) |
import_since |
date | No | Only import emails after this date |
skip_duplicates |
boolean | No | Skip duplicate messages (default: true) |
Response: 201 with the migration job resource.
Error responses:
| Status | Code | Meaning |
|---|---|---|
409 |
conflict | An active migration is already running on this account |
503 |
migration_capacity_reached |
Server-wide migration limit reached (retryable) |
422 |
validation_error | Invalid parameters or mailbox not found |
Cancel migration
POST /api/v1/migrations/{id}:cancel
Scope: migrations:write
Cancels a running migration. The migration must be in an active state (pending, validating, planning, or processing).
Retry migration
POST /api/v1/migrations/{id}:retry
Scope: migrations:write
Retries a failed or cancelled migration. Resets progress to 0 and re-enters the validation pipeline.
Returns 409 if another migration is already running on the account.
Delete migration
DELETE /api/v1/migrations/{id}
Scope: migrations:write
Deletes a migration record. The migration must not be running (cancel it first).
Returns 204 No Content on success.
Rate limits
Migration write operations have a dedicated rate limit of 10 requests per minute per token, separate from the standard API rate limit.
Additionally, the server enforces a global concurrency limit (default: 20 simultaneous migrations). When the limit is reached, new migration requests return 503 with migration_capacity_reached and retryable: true. Wait a few minutes and retry.
Audit events
All migration API actions are recorded in the audit log:
- migration_started — a new migration was initiated
- migration_cancelled — a running migration was cancelled
- migration_retried — a failed or cancelled migration was retried
- migration_deleted — a migration record was deleted
MCP tools
The same migration capabilities are available through the MCP server as 16 tools — 7 for single migrations (test_migration_connection, list_migrations, get_migration, start_migration, cancel_migration, retry_migration, delete_migration) and 9 for bulk migrations (preview_bulk_migration, start_bulk_migration, list_bulk_migrations, get_bulk_migration, cancel_bulk_migration, retry_bulk_migration, resume_bulk_migration, delete_bulk_migration, update_bulk_migration_job_password). Migration write tools require the TREKMAIL_ALLOW_MIGRATION=true environment variable and per-call confirmation parameters. See Connecting AI Agents (MCP) for details.
Bulk Migration API
The Bulk Migration API lets you migrate many accounts at once using a CSV-style data payload. See Bulk Email Migration for the user guide and Bulk Migration CSV Format for the data format.
Endpoints
| Method | Endpoint | Scope | Description |
|---|---|---|---|
| POST | /api/v1/migrations/bulk/preview |
migrations:write |
Preview & validate CSV data |
| POST | /api/v1/migrations/bulk |
migrations:write |
Start a bulk migration batch |
| GET | /api/v1/migrations/bulk |
migrations:read |
List bulk migration batches |
| GET | /api/v1/migrations/bulk/{id} |
migrations:read |
Get batch details with per-job status |
| POST | /api/v1/migrations/bulk/{id}:cancel |
migrations:write |
Cancel entire batch |
| POST | /api/v1/migrations/bulk/{id}:retry |
migrations:write |
Retry failed jobs in batch |
| POST | /api/v1/migrations/bulk/{id}:resume |
migrations:write |
Resume paused batch |
| DELETE | /api/v1/migrations/bulk/{id} |
migrations:write |
Delete batch record |
| PATCH | /api/v1/migrations/bulk/{id}/jobs/{job}/password |
migrations:write |
Update source password for a failed job |
Preview request
POST /api/v1/migrations/bulk/preview
Scope: migrations:write
| Field | Type | Required | Description |
|---|---|---|---|
data |
string | Yes | CSV data (one row per line) |
provider |
string | No | gmail, outlook, yahoo, icloud, generic_imap |
source_host |
string | No | IMAP host (if provider is generic_imap) |
source_port |
integer | No | IMAP port (default 993) |
source_security |
string | No | ssl, tls, none |
per_row_server |
boolean | No | Each row has its own server settings (6-column format) |
Response includes categorized rows (valid, invalid_source_email, invalid_destination, etc.), plan limits, time estimate, and storage info.
Start batch request
POST /api/v1/migrations/bulk
Scope: migrations:write
Same fields as preview, plus:
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | No | Batch name (auto-generated if empty) |
folder_strategy |
string | No | all, standard, inbox_only (default: all) |
import_since |
string | No | Date filter (YYYY-MM-DD) |
skip_duplicates |
boolean | No | Skip duplicate messages (default: true) |
idempotency_key |
string | No | Client-provided idempotency key |
Concurrency limits
| Plan | Max rows per batch | Concurrent per account |
|---|---|---|
| Starter | 100 | 2 |
| Pro | 300 | 5 |
| Agency | 1,000 | 10 |
The global server limit (20 concurrent migrations) is shared between single and bulk migrations.
MCP tools
Six bulk migration tools are available via MCP: preview_bulk_migration, start_bulk_migration, list_bulk_migrations, get_bulk_migration, cancel_bulk_migration, retry_bulk_migration. Write tools require TREKMAIL_ALLOW_MIGRATION=true.
Quick fixes
- 403 "insufficient_scope": Your token needs
migrations:readormigrations:write. Create a new token with the correct scopes. - 403 "token_scope_blocked_by_plan": Migration scopes require a paid plan (Starter or higher).
- 409 "active migration running": Cancel the existing migration or wait for it to finish.
- 503 "migration_capacity_reached": The server is at capacity. Retry in a few minutes.
- 422 on test-connection: Check your IMAP credentials, hostname, port, and security setting.
Related articles
Jump to nearby guides that continue the workflow.