Import mailboxes
Connect hundreds or thousands of mailboxes from a spreadsheet, a vendor export, or a pasted list.
Import mailboxes connects many mailboxes in one go. Open Accounts, choose Add account, then Import mailboxes. It takes the file your inbox vendor or your previous sending tool gave you, works out what each column means and where each domain's mail is hosted, and connects the rows in the background.
Only an address and a password are required. Servers, ports and encryption are found for you.
Three other sources skip the file entirely, each reached from the same Add account dialog:
- Inbox vendor: read the mailboxes straight from the vendor you bought them from, with an API key. See import from an inbox vendor.
- Google > Whole Workspace domain: a Workspace super admin authorizes Warmbly once, and every mailbox on the domain connects without a password. See connect a whole Google Workspace domain.
- Microsoft > Whole organization: a Global Administrator consents once, and every licensed mailbox in the organization connects without a sign-in each. See connect a whole Microsoft 365 organization.
All three create the same kind of import as a file: it runs in the background, shows the same progress, and groups failures by cause.
What it reads
- A file: CSV, TSV or XLSX (the active sheet), up to 10 MB. A CSV may separate its columns with commas or semicolons (the separator spreadsheet apps use where the comma is the decimal mark); the header line decides which.
- A pasted list: cells copied from a spreadsheet, CSV text, or one mailbox per line as
address:password,address;passwordoraddress password. The address never contains a colon or a semicolon, so a password that does is read whole.
[email protected]:abcdabcdabcdabcd
[email protected]:abcd efgh ijkl mnopOne import takes up to 5,000 mailboxes. Split a larger file and import the rest separately.
The first row is treated as a header unless it holds an email address. First row is a header in the dialog overrides the guess.
Columns
Every column is matched to a field automatically. The first of these that applies wins:
- A mapping you confirmed before. When you import a file, the column mapping is saved for the workspace against that exact set of headers, so the next file with the same headers maps itself.
- The header name. Warmbly's own template and the column names in exports from Smartlead, Instantly, Saleshandy, Zapmail and InboxKit are recognised, along with the common spellings (
smtp_server,app_password,login,From Email, and so on). A recognised export is named in the dialog. - The values. A column of addresses, of 16-letter Google app passwords, of
smtp.orimap.hostnames, or of port numbers such as587and993places itself even with no header. - Jev, when the instance has TypeSafe configured, for columns nothing above placed. Jev sees the header text and a description of the values (for example "16 lowercase letters" or "hostnames"), never a value.
Every column can be reassigned by hand, or set to be ignored. Password columns are masked in the dialog and never shown again.
| Field | Holds |
|---|---|
email | The mailbox address. The only column that has to be mapped |
name, first_name, last_name | The sender name. Without one, it comes from the address (alex.rivera@ becomes Alex Rivera) |
password | The mailbox password |
app_password | An app password. Preferred over password on providers that need one |
smtp_password, imap_password | A password for one server only |
username, smtp_username, imap_username | The sign-in name, when it is not the address |
smtp_host, smtp_port, smtp_security | The outgoing server. Overrides detection |
imap_host, imap_port, imap_security | The incoming server. Overrides detection |
daily_limit | Campaign emails per day |
min_wait | Seconds between sends |
warmup | Warmup on or off (yes/no, true/false, on/off) |
warmup_start, warmup_max, warmup_increase, warmup_reply_rate | Warmup's first-day volume, daily ceiling, daily increase, and reply percentage |
reply_to | A reply-to address |
signature | The signature, as plain text |
tags | Tag names, separated by commas, semicolons or vertical bars, up to 20 per row |
timezone | The mailbox's time zone |
Security columns accept SSL, TLS, SSL/TLS and STARTTLS, and the true/false SSL columns some exports use. Without one, security follows the port.
Where the servers come from
Servers are found once per domain, from DNS and the provider's own published settings, in this order:
- Known consumer domains (
gmail.com,outlook.com,yahoo.com,icloud.comand the like). - The domain's MX records, which identify Google Workspace, Microsoft 365, Zoho (with its data centre region), GoDaddy, Namecheap Private Email, IONOS, Hostinger, Fastmail, Yahoo, iCloud, Migadu, Purelymail, Rackspace, OVHcloud, Yandex and GMX.
- The domain's own Mozilla autoconfig file.
- The Thunderbird ISPDB, on Warmbly Cloud and on a self-host that sets
MAILHOST_ISPDB=true. - RFC 6186 SRV records.
The preview lists each domain with its provider, the servers found, and whether SPF, DKIM and DMARC are published. smtp_host and imap_host columns, and the port and security columns, override what detection found. A domain nothing finds needs those columns, or the servers entered on each row after the import.
Each mailbox is labelled with where it is hosted and how it signs in. The API returns these as mail_host and auth_method; a mailbox whose host is not recorded yet, such as one connected before the labels existed, is classified in the background from its domain.
What each provider needs
| Host | The password must be | Where to get it |
|---|---|---|
| Google Workspace, Gmail | A 16-letter app password. Spaces are removed for you. None on a Workspace domain an admin grant covers | myaccount.google.com/apppasswords, after turning on 2-Step Verification. See Gmail and Google Workspace |
| Microsoft 365, Outlook.com | No password: each mailbox connects with Microsoft sign-in, or through an admin grant when one covers the domain | The Sign in button on the row |
| Yahoo Mail | An app password | login.yahoo.com/account/security |
| AOL Mail | An app password | login.aol.com/account/security |
| iCloud Mail | An app-specific password | account.apple.com, under Sign-In and Security |
| Fastmail | An app password with IMAP and SMTP access | Settings, Privacy and Security, Manage app passwords |
| Yandex Mail | An app password | id.yandex.com/security/app-passwords |
| Zoho Mail | The account password, or an app password when two-factor authentication is on | Zoho Accounts for your region, under Security, App Passwords |
| GoDaddy, Namecheap Private Email, IONOS, Hostinger, OVHcloud, Migadu, Purelymail, Rackspace Email, GMX | The mailbox password | Your provider's control panel |
| Proton Mail | Cannot connect this way | See Proton Mail below |
| Anything else | The mailbox password | Your provider. Servers come from autoconfig, the ISPDB, SRV records, or your columns |
A Google row whose password is not a 16-letter app password is flagged in the preview before anything is tried: Google refuses the account password over IMAP and SMTP. On an instance that connects new Gmail mailboxes with Google sign-in (gmail_oauth_connect in GET /auth/config), such a row waits for sign-in instead, like a Microsoft row.
Microsoft
Exchange Online no longer accepts passwords over IMAP, so Microsoft 365 and Outlook.com rows connect with Microsoft sign-in. The import parks them as needs sign-in and the rest of the file carries on. Each has a Sign in button that opens Microsoft's sign-in with the address already filled in. When that address connects, from the row or by any other route, the row closes and the import's settings are applied to the mailbox.
A Microsoft 365 admin can grant consent once for the whole organization, after which each sign-in is one click. To skip the sign-ins altogether, connect the whole organization instead: rows on its domains then connect with no sign-in at all. Microsoft has also announced that SMTP AUTH with basic authentication becomes disabled by default for existing tenants at the end of December 2026, which is another reason these mailboxes use sign-in rather than a password.
Proton Mail
Proton Mail offers no IMAP or SMTP sign-in to other apps; only its Bridge does. Proton rows are flagged as unable to connect. On a self-hosted instance whose worker runs on the machine the Bridge is on, map smtp_host and imap_host columns (and ports) to the Bridge and use the Bridge's own password. See local mail relays.
Import from an inbox vendor
Choose Add account, then Inbox vendor, pick the vendor and enter what it asks for. Warmbly checks the key with the vendor before saving it, lists the mailboxes in that vendor account (marking the ones already in the workspace), and imports the ones you pick, or every one not yet connected.
| Vendor | Asks for | Where to find the key |
|---|---|---|
| InboxKit | API key and workspace ID (a UUID) | Settings > API & Integrations in the InboxKit dashboard |
| Zapmail | API key; optionally a workspace ID (blank is your primary workspace) and a mailbox type (GOOGLE or MICROSOFT, blank imports both) | Settings > Integrations > API in the Zapmail dashboard |
| Mailforge | API key | Settings > API keys in the Mailforge dashboard |
| Infraforge | API key; optionally a workspace ID (blank imports every workspace) | Settings > API keys in the Infraforge dashboard |
| Maildoso | API key (a personal access token) | Settings > API Keys in the Maildoso dashboard |
| Cheap Inboxes | API key, starting with ci_live_ | Integrations > API in the Cheap Inboxes dashboard |
| ScaledMail | API key and organization ID | Settings in the ScaledMail dashboard |
One vendor account lists up to 10,000 mailboxes.
- Credentials are read when each row is worked. Picking mailboxes stores only which ones you picked. The password, app password and servers of each are fetched from the vendor at the moment its row connects, and the row is then judged exactly like a file row: Google mailboxes need the app password the vendor holds (or an admin grant over the domain), and Microsoft mailboxes wait for sign-in unless a grant covers them.
- The key is sealed and never shown again. The API key and IDs are sealed with the workspace's own encryption key. The list of connections shows each one's vendor, label, status and mailbox count, never the key. Update replaces the key after checking the new one with the vendor.
- Passwords the vendor rotates are picked up. An SMTP and IMAP mailbox that came from a vendor and has stopped with an unresolved connection error is looked at every 15 minutes. When the vendor now holds a different password for it, Warmbly verifies that password against the server and reconnects the mailbox with it. Each mailbox is tried at most once every 6 hours, so a password that still fails is not retried on every pass.
- A refused key marks the connection. When the vendor stops accepting the key, the connection shows as invalid with the vendor's reason, and rows that needed it fail as
vendor_unauthorizeduntil the key is updated. - Deleting the connection keeps the mailboxes. They stay connected and keep sending; they are no longer reconnected automatically when the vendor rotates a password.
Connect a whole Google Workspace domain
A Google Workspace super admin can authorize Warmbly for the whole domain with domain-wide delegation. Every mailbox on the domain then connects through that one grant: no app passwords, nothing that expires when someone changes a password, and nothing for each mailbox owner to do. It is the recommended way to connect Workspace mailboxes.
Choose Add account, then Google, then Whole Workspace domain. The dialog shows a client ID and the scopes to authorize. On a self-hosted instance the option stays switched off until the operator has set up a Google service account; see whole-domain mailbox connects.
First, the super admin authorizes the client ID. This has to happen before the domain is proved, because Warmbly checks the authorization straight away:
-
Sign in to admin.google.com as a super admin and go to Security > Access and data control > API controls, then Manage domain-wide delegation.
-
Choose Add new and paste the client ID the dialog shows. It is a long number; it never ends in
apps.googleusercontent.com. -
Enter exactly these three scopes, comma separated:
https://www.googleapis.com/auth/gmail.modify,https://www.googleapis.com/auth/gmail.settings.basic,https://www.googleapis.com/auth/admin.directory.user.readonly -
Choose Authorize, and allow a few minutes for Google to apply it.
Then, back in Warmbly, enter the domain and a super admin address on it, and prove the domain as below.
Prove the workspace controls the domain
The client ID belongs to the instance, not to your workspace, so authorizing it says nothing about which workspace asked. A grant is recorded only for the workspace that proves it controls the domain, in one of two ways:
-
Sign in as the administrator. When the instance has a Google sign-in app, Warmbly opens Google's sign-in for the admin address you entered. The sign-in has to be that exact address, verified by Google, on that Workspace domain.
-
Publish a DNS record. Always available, and the only way on an instance without a Google sign-in app. Add this
TXTrecord at your DNS provider, then confirm:Type Name Value TXT_warmbly.<domain>warmbly-verify=<value>The value is unique to your workspace and that domain, so a record published for another workspace proves nothing for yours. It is the same record that proves the domain for a root redirect, so one record serves both. DNS changes can take a while to appear; confirm again once the record resolves.
A sign-in link is valid for 15 minutes, works once, and only for the member who started it, in the same workspace. Recording the grant also needs a recent confirmation of your own sign-in.
After the proof, Warmbly checks the grant itself: it reads the admin's own Gmail profile and the domain's user directory, and the directory must list the address as a super administrator. A change in the Admin console can take a few minutes to apply, so a refusal straight after saving it is worth one more try. The grant covers the domain and every other domain that appears on its users' addresses. Making the grant again for the same domain re-verifies and updates it rather than adding a second one.
The admin address is used only to read the directory, so you can pick which mailboxes to connect. It is not connected itself, and no token for it is stored. The first two scopes are the same ones a mailbox connected with Google sign-in holds; the third reads the list of users.
Pick users from the directory, or connect every active one not yet in the workspace. A user whose mailbox is already here on its own Google sign-in is marked as one to move: connecting it puts that mailbox onto the grant in place, keeping its history, campaigns and warmup, and connecting everyone includes it. Each mailbox is checked against Gmail as it connects and runs on Gmail's API, like a mailbox connected with Google sign-in. No token is stored for any of them: the backend mints a short-lived one each time a worker needs it.
The grant is checked again every hour. When Google stops honoring it (the entry was removed in the Admin console, or a scope was dropped), the grant shows as invalid and its mailboxes stop. A check that gets no answer from Google changes nothing. When a later check succeeds, the mailboxes that stopped because of it are put back to work on their own; one you switched off stays off. Check again runs the check straight away. Deleting the grant stops every mailbox it connected.
Connecting mailboxes through a grant and deleting a grant both reach a whole domain's mail, so like recording one they need a recent confirmation of your sign-in.
Connect a whole Microsoft 365 organization
A Global Administrator can approve Warmbly once for the whole Microsoft 365 organization. Mailboxes then connect through Microsoft Graph with application permissions: no sign-in per mailbox. It is the recommended way to connect Microsoft 365 mailboxes.
Choose Add account, then Microsoft, then Whole organization, and have a Global Administrator (or Privileged Role Administrator) sign in on the Microsoft consent screen that opens and choose Accept. Warmbly records the organization only when the person who signed in holds one of those roles. That is the only step on the Microsoft side, and it happens once. On a self-hosted instance the option needs the operator's Microsoft app set up first; see whole-domain mailbox connects. The consent gives the instance's Microsoft app these application permissions in the organization:
| Permission | What it is for |
|---|---|
Mail.ReadWrite | Read replies and move messages |
Mail.Send | Send mail |
User.Read.All | List the organization's users, so you can pick which mailboxes to connect |
The organization that is recorded is the one the administrator signed in to, as Microsoft reports it when the consent completes, so a grant can only ever name the organization that consented. Warmbly then obtains a token for it and reads its users; the domains on their addresses (guests excluded) become the domains the grant covers. The consent link is valid for 15 minutes, works once, and only for the member who started it, in the same workspace. Recording the grant needs a recent confirmation of your own sign-in, as do connecting mailboxes through it and deleting it. Consenting again for the same organization updates the grant rather than adding a second one.
Application permissions reach every mailbox in the organization. Microsoft lets an Exchange administrator narrow that to the mailboxes you choose, and we recommend it. With an application access policy, in Exchange Online PowerShell:
Connect-ExchangeOnline
# A mail-enabled security group holding the mailboxes Warmbly may use
New-DistributionGroup -Name "Warmbly senders" -Type Security -PrimarySmtpAddress warmbly-[email protected]
Add-DistributionGroupMember -Identity "Warmbly senders" -Member [email protected]
# <app id> is the Application (client) ID of the app you consented to, under Enterprise applications in the Microsoft Entra admin center
New-ApplicationAccessPolicy -AppId <app id> -PolicyScopeGroupId warmbly-[email protected] -AccessRight RestrictAccess -Description "Warmbly sends only from these mailboxes"
Test-ApplicationAccessPolicy -Identity [email protected] -AppId <app id>Microsoft's newer RBAC for Applications does the same with a management scope and role assignments (New-ManagementScope, then New-ManagementRoleAssignment -App <app id> -Role "Application Mail.ReadWrite" and "Application Mail.Send" with -CustomResourceScope). Its scoped assignments add to what the consent grants, so remove the organization-wide Mail.ReadWrite and Mail.Send consent in Microsoft Entra when you move to it. A mailbox outside the policy is refused when it connects.
Pick users from the directory, or connect every enabled one not yet in the workspace. Only users with a mail address are listed. A mailbox already here on its own Microsoft sign-in is marked as one to move, as with Google: connecting it puts it onto the grant in place, and connecting everyone includes it. Moving is optional for Microsoft mailboxes; their own sign-in keeps working. Each mailbox is checked against Microsoft Graph as it connects; a disabled account, or a user without an Exchange Online license, has no mailbox to connect and is refused. As with Google, no token is stored: the backend mints one each time a worker needs it. The grant is checked every hour, its mailboxes stop when the consent is withdrawn and restart when a check succeeds again, a check that gets no answer from Microsoft changes nothing, and deleting it stops every mailbox it connected.
When a file meets an admin grant
A file or pasted list does not need to know about grants. When an active grant covers a row's domain, the row connects through it:
- a Google Workspace row connects through the domain's Google grant, and any password on the row is ignored
- a Microsoft 365 row connects through the organization's grant instead of waiting for a sign-in
The same holds for rows from an inbox vendor. The preview marks these rows, and each connected mailbox is labelled with the sign-in method delegated. A grant that stops working fails its rows as mailbox_grant_inactive; check the grant, then retry them.
Mailboxes already connected
An address already in the workspace, connected by anyone, is matched case-insensitively. If a mailbox is already connected decides what happens:
- Update (the default): the new password replaces the stored one after it is verified against the server, and the mapped settings are applied. The sender name changes only when the file names one.
- Skip: the mailbox is left as it is and the row is marked skipped.
A mailbox connected with Google or Microsoft sign-in only takes the settings; there is no password to replace. When an active grant covers its domain, the row moves it onto the grant instead, in place, keeping its history, campaigns and warmup (see moving off per-mailbox Google sign-in); Skip leaves it as it is. When the same address appears twice in one file, only the first row is imported and the later ones are skipped as Listed twice in the file.
Settings for every mailbox
The dialog sets these for every mailbox the import connects or updates. A mapped column wins over them for its own row.
- tags
- daily limit
- time between sends (in minutes in the dialog; the
min_waitcolumn is in seconds) - warmup on or off, with its start, maximum, daily increase and reply rate
- reply-to, signature and time zone
Tags are added to the ones a mailbox already has. A tag named in the tags column that does not exist yet is created. A setting that cannot be applied never fails its row: the mailbox is connected and the row's message says what did not apply. A value that cannot be read at all, such as text in a limit column, fails that row before it is tried. See sending behavior and warmup for sensible values.
Tracking domains and root redirects
The review step lists each domain in the import, and two choices can be made per domain there. Both are applied as the import connects the domain's mailboxes, and both can be changed later on sending domains.
- Tracking domain. The subdomain that carries the opens and clicks of every mailbox on the domain. Warmbly offers one already in use by a verified mailbox on the domain, or one whose DNS already points at this instance (it tries
track,t,link,links,click,go,emailandtrk), or suggeststrack.<domain>. When a connected inbox vendor account holds the domain and its API can write DNS records, Warmbly writes theCNAMEthrough the vendor for you. Otherwise you add it; the host is set either way, and links switch to it once the record resolves. See custom tracking domain. - Root redirect. A website address that visitors to the bare domain are sent to, such as
https://yourcompany.com. It is set up once the import has connected a mailbox on the domain. When a connected inbox vendor account holds the domain and can forward it, the vendor's own forwarding is used and there is no DNS to add. Otherwise Warmbly serves the redirect itself once DNS proves you control the domain. See root redirects and domains held by an inbox vendor.
A setting that cannot be applied does not fail the row: the mailbox connects and the row's message says what did not apply. In the API these are the tracking_domains and redirects objects in options, each keyed by domain, up to 500 domains each.
While it runs
The import runs on the server. Closing the tab does not stop it, and everyone in the workspace who can manage mailboxes sees its progress live, with the mailbox list filling in behind it. Recent imports in the dialog reopens one later.
Rows connect 8 at a time, and at most 3 at once against any one mail host, since providers throttle bursts of sign-ins from one address. Each credential is verified against the live server before it is saved, exactly like a single connect, so wrong credentials fail here rather than at the first send.
Rows past the workspace's mailbox allowance fail as Mailbox limit reached; the preview says how many will fit. Raise the allowance and retry them.
Cancelling stops the rows not yet started. Rows already connecting finish.
When rows fail
Failures are grouped by cause, each with the fix. The same keys appear as cause on each row in the API.
| Cause | Title |
|---|---|
missing_email | No email address |
invalid_email | Not an email address |
duplicate_row | Listed twice in the file |
missing_password | No password |
unknown_servers | Mail servers not found |
invalid_value | A value could not be read |
microsoft_signin | Connect with Microsoft sign-in |
google_signin | Connect with Google sign-in |
provider_unsupported | Provider cannot connect over IMAP |
allowance_reached | Mailbox limit reached |
no_worker | No worker available |
creator_removed | Import owner left the workspace |
vendor_unauthorized | Vendor refused the API key |
vendor_unreachable | Vendor did not return the credentials |
mailbox_grant_not_configured | Admin connections are not set up here |
google_delegation_unauthorized | Google refused the domain-wide delegation |
microsoft_consent_missing | Microsoft 365 admin consent is missing |
mailbox_grant_mailbox_unreachable | No mailbox for this account |
mailbox_grant_domain_mismatch | Domain not covered by the grant |
mailbox_grant_inactive | The admin grant stopped working |
internal | Something went wrong |
google_app_password_required | Google needs an app password |
google_bad_credentials | Google did not accept the app password |
google_imap_disabled | IMAP is turned off in Google |
google_web_login_required | Google wants a browser sign-in first |
microsoft_smtp_auth_disabled | SMTP sign-in is turned off in Microsoft 365 |
microsoft_security_defaults | Microsoft security defaults block passwords |
microsoft_conditional_access | A Microsoft sign-in policy blocked this |
microsoft_basic_auth_disabled | Microsoft needs Microsoft sign-in |
microsoft_bad_credentials | Microsoft did not accept the password |
yahoo_app_password_required | Yahoo needs an app password |
aol_app_password_required | AOL needs an app password |
icloud_app_password_required | iCloud needs an app-specific password |
zoho_app_password_required | Zoho refused the password |
fastmail_app_password_required | Fastmail needs an app password |
yandex_app_password_required | Yandex needs an app password |
imap_disabled | IMAP is turned off for this mailbox |
account_locked | The account is locked or disabled |
too_many_logins | Too many sign-in attempts |
auth_unavailable | The server does not take a password here |
auth_refused | The server refused the sign-in |
host_not_found | The server name does not exist |
host_unreachable | The server could not be reached |
port_blocked | The mail port looks blocked |
tls_failed | The secure connection failed |
cleartext_refused | Encryption is required |
timeout | The server did not answer in time |
temporary | The server asked to retry later |
server_declined | The server did not accept the connection |
Then fix them without re-uploading:
- Fix one row: enter a new password or app password, a sign-in username, or the servers, and the row is queued again.
- Retry a group: requeue every failed row with one cause, optionally with one new password for all of them.
- Download failed rows: a CSV of every row that did not connect, with its line number, the columns you uploaded minus passwords, and
status,problemandhow_to_fix. Add the passwords back before uploading the fixed file.
A retry is possible for 7 days after the import finishes. After that the row's credentials are gone and it has to be imported again.
What is kept
-
Credentials of rows that did not connect are kept, sealed with the workspace's own encryption key, for 7 days after the import finishes so a retry works, then deleted.
-
A finished import and its rows (address, status, cause, and the non-password cells shown in the download) are deleted after 30 days.
-
A connected mailbox's credentials are stored exactly like any other mailbox's.
-
An inbox vendor connection (its sealed key and IDs) is kept until you delete it. So is an admin grant, which holds the domains it covers, the tenant, and for Google the admin address; it holds no token.
The saved column mappings and vendor connections travel with a workspace export. Imports themselves do not, and neither do admin grants: a grant is recorded only after the workspace proves the domain or organization on the instance it runs on, and an archive proves nothing. The mailboxes a grant connected do travel. On the destination, make the grant again, then pick those users in its directory (they are listed as already connected, so connecting every user not yet here skips them), or import a file of their addresses with Update for existing mailboxes. Each one relinks the mailbox that arrived, with its history and settings, rather than adding a second one.
API
The import is available to a signed-in session under /emails/imports, never to an API key, because it carries passwords. Vendor connections (/emails/vendors), admin grants (/emails/grants) and sending domains (/emails/domains) are session-only for the same reason. See endpoints for the routes. POST /emails/onboarding/smtp-imap/bulk remains for connecting up to 50 SMTP and IMAP mailboxes in one synchronous call.