MailMove
imapsync, with a queue and a paper trail.
imapsync, with a queue and a paper trail.
Scan this with your authenticator app, then type the code it shows.
Servers, migrations and credentials are kept apart per customer.
No customers yet
Add a customer to start tracking their servers, migrations, and credentials.
No migrations yet
Start a migration and it will show up here.
No servers yet
Add the mail servers you migrate between. You need at least two.
A bootstrap service account for this customer only, used to auto-create the per-migration Google Workspace service account from the "New server" form instead of a trip through the Cloud console. Scoped to this customer, like everything else here.
Checking…
Files uploaded via "Upload PST files" on the New migration form, waiting to be imported. Auto-deleted after a successful import unless "Auto-wipe stored mailbox credentials" in Settings is off — then they sit here until removed by hand.
No uploaded PST files
Files you upload from "New migration" will show up here until they're imported.
Runs against this customer's tenant directly from this server — PowerShell for Exchange Online, REST API for Google Workspace.
| When | Who | What | Detail |
|---|
Tạo app đăng ký trên Entra ID để Toolbox và các server kiểu "Exchange Online (Microsoft 365)" đăng nhập được — làm đủ 5 bước dưới đây trước khi thêm server.
Azure Portal → Entra ID → App registrations → New registration. Đặt tên gợi nhớ, ví dụ Exchange.ManageAsApp.
Vào trang Overview của app vừa tạo, lưu lại hai giá trị này — sẽ cần nhập khi thêm server trong app này:
Directory (tenant) ID và Application (client) ID
Certificates & secrets → New client secret. Copy giá trị secret ngay lúc tạo — Azure chỉ hiện một lần, đóng trang là mất, phải tạo secret mới nếu quên copy.
API permissions → Add a permission → tab APIs my organization uses → tìm Office 365 Exchange Online.
Không chọn Microsoft Graph ở bước này — đó là API khác, tìm Exchange.ManageAsApp trong Graph sẽ luôn ra "No results".
Chọn Application permissions → tick cả hai quyền sau, đừng chỉ tick một:
Exchange.ManageAsApp — cho Toolbox (Connect-ExchangeOnline, các lệnh PowerShell).
IMAP.AccessAsApp — cho việc đăng nhập IMAP thật vào mailbox (migration nguồn/đích M365). Hai quyền này độc lập nhau — có cái này không tự động có cái kia.
Chỉ tick Exchange.ManageAsApp mà quên IMAP.AccessAsApp là nguyên nhân phổ biến nhất khiến Toolbox chạy bình thường nhưng migration lại báo lỗi 2 NO AUTHENTICATE failed — cùng một token, nhưng Exchange kiểm tra quyền IMAP riêng với quyền PowerShell.
Bấm Add permissions, rồi Grant admin consent for <tenant> — thiếu bước consent này thì quyền vừa thêm chưa có hiệu lực.
Exchange.ManageAsApp thôi chưa đủ — service principal của app còn phải giữ role Exchange Administrator, nếu không mọi lệnh Toolbox sẽ bị từ chối, kể cả lệnh chỉ đọc.
Entra ID → Roles and administrators → Exchange Administrator → Add assignments → tìm theo tên app.
Hoặc bằng PowerShell (Microsoft Graph module):
$sp = Get-MgServicePrincipal -Filter "AppId eq '<APP_ID>'"
$role = Get-MgDirectoryRole -Filter "DisplayName eq 'Exchange Administrator'"
New-MgDirectoryRoleMemberByRef -DirectoryRoleId $role.Id `
-BodyParameter @{ "@odata.id" = "https://graph.microsoft.com/v1.0/directoryObjects/$($sp.Id)" }
Customers → chọn customer → Add server. Chọn Type = Exchange Online (Microsoft 365), Sign-in = OAuth2 — Entra app, điền 3 giá trị đã lưu ở bước 1–2.
Lưu server, rồi bấm Test sign-in để xác nhận lấy token thành công trước khi dùng thật.
Toolbox chạy được (List mailboxes, Check IMAP access...) nhưng bước Verify credentials của migration báo Host2 failure: Error login ... auth [XOAUTH2 accesstoken]: 2 NO AUTHENTICATE failed — gần như luôn là do:
Nếu dùng tính năng kéo danh sách mailbox tự động từ tenant (Discovery), thêm quyền Microsoft Graph — Application permissions:
Nhớ Grant admin consent sau khi thêm.
Google Workspace dùng service account + domain-wide delegation thay vì OAuth consent thường — không có UI "đăng nhập" nào để bấm, toàn bộ quyền được cấp trước bởi Super Admin. Làm đủ các bước dưới đây trước khi thêm server kiểu "Google Workspace".
console.cloud.google.com → tạo project mới (hoặc dùng project sẵn có). Ghi lại Project ID — dạng chữ thường/số/gạch ngang như my-company-migrate-2026, khác với tên hiển thị (Project name).
Nếu project thuộc 1 Google Cloud Organization có policy bảo mật mặc định, việc tạo key cho service account (bước 3) có thể bị chặn ngay từ đầu — xem cảnh báo ở callout "Service account key creation is disabled" bên dưới trước khi tốn công làm tiếp.
Đây không phải service account dùng để đồng bộ mail — nó chỉ là "chìa khoá" để app tự động tạo ra service account thật ở bước 3, thay vì bạn phải bấm tay trên Cloud Console mỗi lần thêm khách hàng mới.
IAM & Admin → Service Accounts → Create Service Account — đặt tên bất kỳ, ví dụ imapsync-bootstrap.
IAM & Admin → IAM → Grant Access → cấp cho service account này 2 role:
Service Account Admin và Service Account Key Admin
Mở lại service account đó → tab Keys → Add Key → Create new key → JSON → tải file JSON key về.
Vào customer đó → tab Servers → cuộn xuống thẻ Google Cloud — provisioning key → dán nguyên văn nội dung file JSON vừa tải → Save key.
Key này scoped theo từng customer, giống mọi credential khác trong app — không dùng chung giữa các customer.
Servers → Add server → Type = Google Workspace. Điền GCP project ID (project ở bước 1) và Service account ID.
"Service account ID" là tên bạn tự đặt mới (chữ thường/số/gạch ngang, bắt đầu bằng chữ cái, 6-30 ký tự — vd imapsync-migrate), không phải giá trị có sẵn nào cả. Nhầm phổ biến: dán vào đây dãy số Unique ID của service account bootstrap — sai, sẽ không tạo được gì.
Bấm Tạo service account tự động — app tự bật Gmail API, tạo service account mới, tạo JSON key, và điền sẵn vào ô "Service account JSON key" bên dưới. App cũng hiện ra Client ID (một dãy số, gọi là uniqueId) cần cho bước 5.
Đăng nhập admin.google.com → Domain-wide delegation bằng tài khoản Super Admin của domain.
Add new → Client ID: dán Client ID app vừa hiện ở bước 4.
OAuth scopes — dán 1 dòng, các scope cách nhau bằng dấu phẩy, không xuống dòng riêng từng cái:
https://mail.google.com/,https://www.googleapis.com/auth/admin.directory.user.readonly,https://www.googleapis.com/auth/admin.directory.domain.readonly
Scope đầu (mail.google.com) là bắt buộc cho migration. Hai scope Directory API phía sau chỉ cần nếu muốn dùng Toolbox → Google Workspace (List mailboxes/domains) — bỏ qua nếu chỉ cần chạy migration.
Bấm Authorize. Nếu tenant đã có Client ID này rồi (từng sửa trước đó), sửa lại đúng field scope hiện có thay vì Add new lần nữa.
Nếu đã thêm 2 scope Directory API ở bước 5, quay lại form server, điền Admin email to impersonate — phải là địa chỉ email của một Super Admin thật trong domain, Directory API từ chối impersonate user thường.
Có field này thì nút Pull from tenant (ở New migration) và tab Toolbox → Google Workspace mới dùng được.
Lưu server, vào Toolbox → Google Workspace, chọn server vừa tạo, bấm Run ở task List mailboxes hoặc List domains — ra danh sách nghĩa là toàn bộ chuỗi quyền đã đúng.
Sẵn sàng tạo migration: chọn server này làm From hoặc To khi khai báo migration mới.
Gặp khi tạo key ở bước 2 (thủ công) hoặc app tự tạo key ở bước 4. Nguyên nhân: Organization Policy iam.disableServiceAccountKeyCreation đang enforce trên project hoặc cả tổ chức — mặc định bật với org mới ("Secure by Default").
gcloud resource-manager org-policies disable-enforce iam.disableServiceAccountKeyCreation --project=<project-id>
App chỉ tự bật Gmail API. Hai API sau phải bật tay ít nhất 1 lần cho mỗi project mới — lỗi luôn kèm sẵn link để bật, chỉ cần bấm Enable rồi đợi 1-2 phút cho lan truyền:
GCP IAM API có độ trễ lan truyền vài giây — nếu bấm "Tạo service account tự động" hai lần liền nhau, lần đọc lại có thể hụt. App đã tự retry vài lần cho trường hợp này; nếu vẫn lỗi, đợi vài giây rồi bấm lại là qua.
Live status of this server — not any customer's mail server. Refreshes every 10s while open.
Operational knobs only. Secrets and process-level flags stay in .env on the server.
Test IMAP server on this box — no real customer data.
Sandbox management is off
Set ALLOW_SANDBOX=true in .env and restart the service.
Dovecot with a self-signed cert — testing only.
No mailboxes yet
Use "Quick pair" or "Add mailbox".