Migrate Google Workspace email with imapsync (OAuth2 service account)
When a client wants to move a domain's email hosted on Google Workspace to our servers, they can use imapsync. Google no longer lets third-party applications connect over IMAP with the account's normal password. You need to use OAuth 2.0 or, for a one-off migration of a few accounts where the policy allows it, an app password.
In this guide we explain the two valid ways of authenticating the Google Workspace source and, specifically, how to set up a service account with domain-wide delegation. The same credential can authenticate the authorised mailboxes without touching each user, although imapsync has to synchronise them one by one.
Why the normal password no longer works
Google has phased out access for "less secure apps" (basic auth):
- 15 June 2024: the less secure apps setting is removed from the Admin console. Administrators can no longer turn it on (existing connections kept working for a while).
- 14 March 2025: Google began turning off third-party app access with the normal password on Workspace accounts.
- 1 May 2025: the announced transition for these apps ended.
So do not set up imapsync with the normal password. OAuth2 delegation is the right option for many accounts; an app password is a per-user exception that requires 2-Step Verification and that the administrator has not restricted it.
The two options
| Service account (XOAUTH2) | App passwords | |
|---|---|---|
| Best for | Migrating a whole domain | Migrating one or a few accounts |
| Need to touch each user | No | Yes (turn on 2-Step Verification + generate a code) |
| What you need | 1 JSON file (the admin creates it once) | A 16-character code per account |
| Access required | Workspace admin + Google Cloud | Access to each account |
If you are only migrating one or two accounts, app passwords (described in Move Gmail accounts to Hostsuar) are the quickest. For a whole domain, carry on with the service account.
Set up the service account (done by the Workspace administrator)
These steps are carried out only once by a super administrator of the Google Workspace domain. At the end you get a JSON file containing a private key. Delegation can allow impersonating domain users for the granted scopes: a list of mailboxes written in a script does not technically limit that power.
1. Create or select a project in Google Cloud
Go to console.cloud.google.com with the administrator account and create a new project (for example migracion-correo) or select an existing one.
2. Review the Google Cloud project
IMAP XOAUTH2 authentication uses the mail scope authorised in the domain delegation. Enabling the Gmail API does not replace that authorisation and is not a requirement imapsync documents for its JSON flow. You can enable it if other tools in the project will use the API, but do not grant the service account extra IAM roles for this migration.
3. Create the service account and its JSON key
Go to APIs & Services → Credentials → Create credentials → Service account and give it a name. The wizard will then offer two steps marked (optional): "Permissions / Grant this service account access to project" (select a role) and "Principals with access". Leave both empty and continue: this service account does not need any IAM role on the project, because access to the mailboxes is granted in step 4 (domain-wide delegation), not here. Click Done to create it.
Then, inside the service account, go to the Keys → Add key → Create new key tab and choose the JSON format (do not use P12).
A file with this structure will be downloaded, which you will rename to secret.xoauth2.json:
{ "type": "service_account", "project_id": "...", "private_key_id": "...", "private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n", "client_email": "xxx@proyecto.iam.gserviceaccount.com", "client_id": "1234567890...", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://accounts.google.com/o/oauth2/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url": "..." }
Note down the client_id value from the JSON (a long number): you will need it in the next step. It is the service account's OAuth2 identifier, and it is exactly what goes in the Client ID field of the domain-wide delegation (step 4).
4. Authorise domain-wide delegation
This step takes place in the Google Workspace Admin console (admin.google.com), which is a different site from the Google Cloud Console where you created the service account.
The quickest way is to go straight to the delegation URL (signed in as super administrator):
https://admin.google.com/ac/owl/domainwidedelegation
Or navigate: Menu (☰) → Security → Access and data control → API controls → "Manage Domain Wide Delegation". Once there, click Add new and:
- In Client ID, paste the
client_idfrom the previous step. - In OAuth scopes, enter this scope:
https://mail.google.com/
Very important:
https://mail.google.com/is the scope imapsync's JSON flow requests for IMAP access. Authorise only that scope.gmail.readonlydoes not allow IMAP sign-in. Google documentsgmail.imap_adminas an alternative for clients that explicitly request that scope; adding it in the console does not make imapsync request it, nor does it guarantee that hidden labels will appear.
Click Authorize to save.
5. Check that IMAP is enabled
In the Admin console, go to Apps → Google Workspace → Gmail → End User Access and make sure IMAP access is turned on. The mail client policy for the organisational unit concerned must allow any mail client; restricting it to specific OAuth client IDs can block the service account even if the delegation exists.
With that, the Google side is ready. The secret.xoauth2.json file contains a private key and must be treated as a credential that can impersonate the authorised mailboxes.
Test and run imapsync
This flow requires a version of imapsync that supports JSON service accounts and their XOAUTH2 dependencies. It does not work in the graphical migration interface based on username and password. First run an authentication test for one account:
imapsync \ --host1 imap.gmail.com --ssl1 --sslargs1 SSL_verify_mode=1 --user1 usuario@tudominio.com \ --password1 /ruta/privada/secret.xoauth2.json --authmech1 XOAUTH2 \ --host2 SERVIDOR_IMAP_DESTINO --ssl2 --sslargs2 SSL_verify_mode=1 --user2 usuario@tudominio.com \ --passfile2 "$HOME/.imapsync-destino" --justlogin
Remove --justlogin only once both authentications work. Delegation saves you creating a key per user, but imapsync still runs one synchronisation per mailbox. Test one account first, check labels and counts, and then process the rest in a controlled way. Gmail limits IMAP downloads to 2,500 MB per user per day according to the published limit, which Google may change; when you reach the limit, stop that account and wait before resuming it. For SERVIDOR_IMAP_DESTINO, use the hostname with a valid certificate shown in cPanel's Connect Devices.
Handing over and safely withdrawing the key
- Transfer the JSON through a one-time encrypted exchange, with an expiry and access limited to the person who will run the migration. Do not paste it into the text of a ticket or send it by email.
- On the migration machine, store it outside public directories, owned by a single user and with
0600permissions:chmod 600 secret.xoauth2.json. Do not copy it to repositories, shared backups or command logs. - Limit the delegation to the length of the migration. Once you have finished and verified the mailboxes, remove the domain-wide delegation authorisation, revoke and delete the service account key in Google Cloud and delete every local copy of the JSON.
- If the key was sent through the wrong channel or may have been exposed, revoke it before continuing and generate a new one; deleting only the file does not invalidate a key that has already been copied.
Decide who can run the migration
Authorise this procedure only for the agreed mailboxes and operation. The https://mail.google.com/ scope is not read-only: running imapsync without deletion options does not reduce the permissions anyone who obtains the key would have.
The IMAP policy restricted to OAuth client IDs does not support this delegation flow, according to Google. Do not loosen the policy for the whole organisation for convenience: the administrator should weigh up the unit affected, the duration and restoring the controls, or choose another authorised method.
Before processing the whole set, test one account and keep an inventory of source, destination, skipped folders, errors and last synchronisation. When you wrap up, as well as withdrawing the key and the delegation, check that any temporary policies are back to their intended state.
You may also find useful
- Copy email from Gmail or Google Workspace to Hostsuar Explains how to authenticate a Gmail or Google Workspace account securely to copy its mailbox to Hos...
- Use imapsync over SSH to copy email between providers Shows how to copy a whole mailbox with imapsync over SSH, using TLS and protected files for the cred...
- Archive a domain's incoming and outgoing email in cPanel Set the scope and retention of cPanel's email archive and check how to access it without mistaking i...
- Save your email to your computer before deleting it from the server Compare a local archive, POP download and backup, and check messages and attachments before freeing...
Something wrong or out of date? Tell us and we will review it.