Managing Email Migrations via the API
Manage email migrations through the TrekMail API. Test connections, start imports, monitor progress, cancel, retry, and delete migration jobs.
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
- Sep 9, 2026
The Migration API lets you import email from any IMAP provider into a TrekMail mailbox through an integration or agent. 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.
- Pro and Agency can start, cancel, retry, and delete migrations through the API (
migrations:read+migrations:write). Starter can read migrations via the API and run new ones from the dashboard. - 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 | 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 |
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.
Partial migrations
TrekMail may try to continue a partially completed migration when it is safe to do so. Check the migration status before taking action. If it is no longer progressing, review the source account credentials and limits, then use the retry endpoint or the dashboard's Continue action. Do not assume a partial import will complete without checking its final status.
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, including test, list, start, cancel, retry, resume, password-update, and delete actions for single and bulk migrations. A locally hosted MCP administrator can require explicit approval for migration writes. 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 |
List batches response
GET /api/v1/migrations/bulk is paginated and follows the standard envelope described in API Overview — batches in data, paging in links and meta. Add status to filter and per_page (1-100, default 20) to size the page.
{
"data": [
{ "id": 42, "name": "Acme cutover", "status": "completed",
"total_jobs": 120, "completed_jobs": 118, "failed_jobs": 2,
"progress_pct": 100, "poll_hint_seconds": null,
"summary": { "total_messages_imported": 481203, "total_messages_failed": 17, "total_skipped_duplicates": 2904 },
"started_at": "2026-07-27T09:12:04+00:00", "finished_at": "2026-07-27T14:48:51+00:00" }
],
"links": { "next": null, "prev": null },
"meta": { "current_page": 1, "last_page": 1, "total": 1 }
}
poll_hint_seconds tells you how long to wait before asking again: 5 while a batch is processing, 30 while it is queued or paused, and null once it has finished.
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
Bulk migration MCP tools are preview_bulk_migration, start_bulk_migration, list_bulk_migrations, get_bulk_migration, cancel_bulk_migration, retry_bulk_migration, resume_bulk_migration, delete_bulk_migration, and update_bulk_migration_job_password. A locally hosted MCP administrator can require explicit approval for write actions.
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.