Repository navigation
Migration
Written on 24 September 2026 and brought up to 6.3.4 (27 September 2026, schema 6104), on 26 September 2026, from
hmailserver/docs/Migration.md. The routes from another IMAP server (a mirroring external account), from mbox files, from a Maildir, from Outlook over IMAP and from the upstream hMailServer are in 6.3.3 and later; the webmail's own Other accounts with Gmail and Outlook.com sign-in, the migration jobs (schema 6090) and PST import are new in 6.3.4. Brought up on 5 October 2026 to 6.3.6 (6 October 2026, schema 6108), for what 6.3.6 changes on this page. 6.3.7, the latest release (17 October 2026, schema 6108), is not yet reflected here.
How to bring existing mailboxes into this server. Moving an installation of hMailServer is elsewhere: Upgrading hMailServer for a release-to-release upgrade and the move from the original project up to 5.6 (its 5.7 releases are not upgraded in place: the table below has them), Migrating the Database Backend for a change of database, and Relocating an Installation for another folder or drive, and Backup and Restore for a new machine.
| You are moving | Use | Keeps | Does not keep |
|---|---|---|---|
| One person's own mailbox, by that person | The webmail's Other accounts (6.3.4) | Folders brought over as copies, then new mail collected | Rules, signatures |
| A few mailboxes that must stay in step until the cut-over | An external account with the mirror on - the server collects every folder over IMAP until it is switched off | Folders, every message byte for byte, the five standard flags, the internal date | Subscriptions, custom keywords, ACLs |
| Many mailboxes - hundreds - from an IMAP server, Google Workspace or Microsoft 365, with contacts, calendars and a report per mailbox | A migration: a job per mailbox (6.3.4) | Folders into their special-use counterparts, every message byte for byte, flags and keywords, the date; contacts and calendars | Rules, signatures, shared mailboxes, ACLs, Gmail's labels as labels |
| mbox files (Thunderbird's profile, Apple Mail, a Unix spool) | The Import Tool, one folder per file | Every message, the date from the headers | Flags - mbox has no standard for them |
| A Maildir (Dovecot, Courier) | The Import Tool's Select Maildir | The Maildir++ hierarchy, every message, the flags in the file names | Custom keywords |
| Outlook PST files |
PST import (6.3.4): a migration of kind pst, a job per file into one account, the file copied into the server's PST import directory first |
Folders and their special-use counterparts, messages rebuilt as Internet mail with flags, categories and dates; contacts, calendar items and tasks into the account's address books and calendars; notes and journal entries as messages | Attachments by reference and OLE objects, distribution lists, the 4K-page layout of newer OSTs, a cached Exchange OST, a file protected by Windows Information Protection |
| What PST import refuses or leaves out | Outlook itself, over IMAP: add this server as an IMAP account and drag the folders across | Whatever Outlook uploads: folders, messages, read and flagged state | Anything Outlook does not put on the wire |
| A server of the original hMailServer's 5.7 (5.7.0, 5.7.1 and 5.7.2) | A migration of kind imap from it, with this server installed on another machine and the domains and accounts made here first: setup cannot upgrade a 5.7 database, and from the release after 6.3.7 refuses such an installation before it changes anything; the installers of 6.3.7 and earlier do not look, and must not be run over one (Upgrading hMailServer 18.2) |
What a migration from another IMAP server keeps | The settings, rules and the rest of its configuration, made again here |
| The accounts themselves | The Import Tool's text-file import, or a spreadsheet over REST and hmctl (6.3.4), or SCIM from the identity provider (6.3.4) - first, since every route above needs the account to exist |
Addresses, passwords, quotas |
The external account and its mirror are on the account dialog's External tab in the Control
Panel, and on the Deck's fetch-accounts view; Mirror every folder (MirrorFolders) is what turns
a collection of the INBOX into a copy of every folder. A new external account for the mirror is the
safe choice: one that has been collecting the INBOX alone collects it once more when the mirror is
switched on.
Since 6.3.4. Settings, Other accounts in the webmail. The
person picks their old provider - Gmail, Outlook.com, Yahoo Mail and iCloud Mail fill in the server,
port and encryption and say what each asks for - gives the user name and password, chooses whether
to leave the mail there, and ticks Bring the folders over too. It is an external account like
any other, with the filters on, the host held to public addresses unless the administrator turns
on reader_fetch_accounts_private_addresses, an interval of at least fifteen minutes, and at most
reader_fetch_accounts_max of them (3 by default).
Days to keep messages is per collected message, and means what it means for any external account, POP3 or IMAP: -1 deletes each message from the remote folder once it is safely filed here - a move; 0, the default, leaves every message there, so the two servers stay in step for as long as the account polls; a number of days N deletes a message N days after it was collected. A migration usually runs with the messages left in place until the cut-over, then one last poll and the account is disabled. (From 6.2.25 to 6.3.5 an IMAP account read 0 as "delete" and -1 as "keep", the other way round from a POP3 account; the upgrade to 6.3.6, schema 6106, translated each IMAP account's value so that it goes on doing what it did, and the Control Panel, the Deck, the webmail and the REST API now all describe the one meaning.)
Signing in rather than giving a password. Outlook.com no longer accepts a password from another
mail server, and Gmail takes only an app password. Where an administrator has registered this server
with Google and Microsoft, the page offers Sign in to Gmail and Sign in to Outlook.com: the
person signs in there and grants IMAP access, and the external account logs in with XOAUTH2 - no
password is stored, and the permission can be taken back at the provider. The first collection then
lists the folders to tick, with Gmail's All Mail, Starred and Important unticked so that nothing
arrives twice. The registration is import_oauth_redirect_base_url (the redirect URI is that plus
/portal/oauth/callback) and each provider's client id and secret, on PUT /api/v1/settings.
Schema 6090, since 6.3.4. Moving an organisation needs something the
server runs itself: a job per mailbox with a state, no more load on the source than it will
bear, a job that goes on from where it was after a failure or a restart, a report per mailbox, and
the contacts and calendars beside the mail. It is administered over REST under
/api/v1/migrations and in the Control Deck's Migrations view; there is no COM interface and no
Control Panel page.
-
Create the accounts first - with a spreadsheet import, the Import Tool or SCIM.
-
Create the migration, naming its source:
imap(any IMAP server, a password per mailbox),googleormicrosoft365(each mailbox signed in to by its owner) - orpst, below. A migration runsconcurrencyjobs at once (4 by default, up to 32) atmessages_per_minuteeach. -
Add the jobs - a CSV of
sourceuser,secret,target, up to 5,000 lines, every line checked before any job is made and the first bad line named:sourceuser,secret,target anna@old.example,Anna's old password,anna@example.com carla@example.com,,carla@example.comFor Google and Microsoft 365 the secret is left empty: the answer carries a one-use sign-in link per job for its owner to open, sign in as that mailbox and grant access. A sign-in as anybody else attaches nothing.
-
Start it, and watch each job's state, phase (
mail,contacts,calendars,report), progress and last error in the Deck, or downloadsummary.csvfor the spreadsheet.
What a job does. It lists the source's folders and maps each to one here: the INBOX to the
INBOX, a special-use folder (Sent, Drafts, Junk, Trash, Archive) to the account's own folder of that
use whatever it is called, everything else by name. Every message is copied byte for byte with its
flags, keywords and date. Then the contacts and calendars: from an IMAP server by CardDAV and CalDAV
found by RFC 6764 discovery (or dav_url); from Google by its CardDAV and CalDAV; from Microsoft 365
by Microsoft Graph. A phase that cannot run is skipped with its reason and never fails a job whose
mail is copied.
It survives being interrupted. After every fifty messages and at the end of each folder the job writes its resume marks; whatever stops it - a network failure, a pause, the service restarting - it goes on from those marks, and it checks what it wrote since it started so that each message arrives once, however often it is interrupted. A failure time may mend is retried after 1, 5 and 15 minutes and then hourly; wrong credentials fail the job at once, and Retry takes a mended password.
It is throttled three ways: concurrency per migration, MigrationConnectionsPerHost (4 by
default) across every migration from one source host - a provider counts sessions per client address
- and at most 64 jobs on the server at once.
The report per job says, folder by folder, how many messages the source held, how many were copied
and why any were skipped (duplicate, another_folder, too_large, refused, gone, empty),
then the contacts and calendars, the bytes, the duration and the errors met.
Who may. Reading needs view_accounts and writing manage_accounts in the target's domain; the
server administrator creates a migration, and a domain administrator then sees and adds to it. The
audit trail records migrations and jobs; a job's own progress is not recorded. Jobs are not carried
by a backup: a restore is not a moment in a migration.
Since 6.3.4. The server reads a PST itself, with a reader of this project's own written from
Microsoft's published specifications ([MS-PST] and the documents beside it) and no third-party PST
code. It is a migration of kind pst: one job per file, each into one account, with the same state,
throttle, resume marks, report and Deck view as every other migration.
Off until a directory is named. A job names a file and never a path. The file is looked for only
in the subdirectory named for the target account's domain, inside the directory the setting
pst_import_directory names (PstImportDirectory in hm_settings, set with PUT /api/v1/settings
or on the Control Deck's Settings page). It is empty as shipped, and while it is empty every PST
job is refused with No PST import directory is set on this server.
D:\PstImport\ <- pst_import_directory
D:\PstImport\example.com\archive.pst <- a job for anna@example.com names archive.pst
- Copy the file into the domain's subdirectory, where the service's account can read it. A share on another machine is refused; so is a name that climbs out of the domain's directory by any spelling, link or junction.
- Make the migration and its jobs -
POST /api/v1/migrationswith{"name": "Archives", "kind": "pst"}, then a CSV offile,password,targetlines (the password only for a file that has one) - over REST, withhmctl, or in the Deck's Migrations view. There is no Import Tool button for it on Windows and no COM route. - Start it. It needs
manage_accountsandmanage_mailboxin the target's domain. The rule that a job reads only its own domain's subdirectory holds for everyone, the server administrator included, because the directory is shared between domains.
What comes in. The folders a person sees in Outlook - the IPM subtree - each at its own path, with Sent Items, Deleted Items, Drafts and Junk E-mail found by what the store says they are rather than by their names and filed into the account's own folders of that use. Every message is rebuilt as Internet mail, deterministically, so a resumed job knows what it filed: headers, plain and HTML bodies (and HTML carried in RTF), attachments, embedded messages, S/MIME as it was. Read, flagged, replied, forwarded and draft state come across as IMAP flags, categories as keywords, and the delivery date as the internal date. Contacts go into the account's address book, calendar items and tasks into its calendars (recurrence included), notes and journal entries into mail folders as messages. ANSI files (Outlook 97 to 2002) are read, and an OST where it is a PST in all but its name.
What it refuses, with a sentence saying what to do. The 4K-page layout Outlook 2013 and later
write for an OST, which Microsoft has not published; an OST that caches an Exchange mailbox, whose
folder identifiers the published format does not map; a file protected with Windows Information
Protection, which only Outlook on the protecting machine can open; a missing or wrong password (give
it as the job's secret and retry). A file Outlook still has open pauses the job until it is closed.
Attachments by reference and OLE objects, distribution lists, a contact with no SMTP address, the
attachments of appointments and tasks, and a message over the reader's limits (128 MB of text and data
together) are left out and named in the report; a damaged message is counted unreadable and the
rest of its folder comes in.
The reader runs in a process of its own. Each phase of a job starts the server's own program as
the reader (hMailServer.exe --pst-read on Windows, hmailserver --pst-read on Linux - not a command
for an administrator), hands it the file it opened and checked and nothing else of the service's -
no configuration, no database, no log - and kills it on a pause, a cancel, a restart or the service
stopping, or when it has not answered a request in ten minutes. A file that crashes the reader costs
the message it was on, not the service: a new reader is started and the job goes on. This is crash
containment, not a sandbox: the reader runs as the service's own account with its privileges
taken away, bounded in memory (2 GB committed on Windows, 4 GB of address space on Linux), at a lower
priority and with no handle of the service's but the file's - and it can still reach whatever that
account can reach on the machine. The fixture API.PstImport
runs on Windows; nothing runs it on Linux yet.
The full account, with every limit, refusal and code page, is the Outlook data files (PST) section of Migration.md.
- Rules and filters (Gmail's filters, Outlook's inbox rules, Sieve), signatures, out-of-office replies and forwarding - make them again here.
- Shared mailboxes and permissions: other users' and shared mailboxes are left with a note, and a Microsoft 365 shared mailbox, which nobody signs in as, cannot be a job.
- Subscriptions: every folder is created subscribed.
-
Gmail's labels as labels. Over IMAP a label is a folder; a
googlemigration copies each message once, into the first folder it meets it in, and All Mail brings only what no label held. The star arrives as\Flagged. - Contact groups, and contacts with no address.
- From Microsoft 365, the default contacts folder and the default calendar only.
- From a PST, what the section above lists as left out or refused; for those, Outlook over IMAP is still the route - add this server as an IMAP account in Outlook and drag the folders across.
The full document, with every field, route and refusal, is Migration.md.
See also: The Webmail · The Control Deck · Sign-in and Identity · Connecting a Mail Client · Upgrading hMailServer
hMailServer 6.3.7, the latest release (17 October 2026, schema 6108) · AGPL-3.0-or-later · Repository · Mirror on GitHub · Report a documentation error (a GitLab issue naming the page)
Home — full index
Start here
1. Install and run
- Before You Install
- Installing hMailServer
- Installing on Linux
- Running in a Container
- Profiles and Environment
- The Control Panel
- The Control Deck
- Your First Domain and Mailbox
- Connecting a Mail Client
- The Webmail
- DNS for Your Domain
- Migration
2. Secure it
- Encryption and Certificates
- Database TLS
- Encryption for People
- Stopping Spam
- Stopping Viruses
- Security Hardening
- Secure Defaults
- The Service Account
- Secrets at Rest
- Sign-in and Identity
- Security Policy
3. Operate it
- Monitoring and Health
- The SNMP Agent
- Backup and Restore
- Message Storage
- Compliance and eDiscovery
- Troubleshooting
- Diagnosing Stalled Mail
- Relocating an Installation
- Upgrading hMailServer
- Upgrading Guide
- The Update Feed
- Migrating the Database Backend
- High Availability Runbook
- Warm Standby
- Runbooks Digest
4. Extend it
- Rules and Sieve
- Aliases Lists and Public Folders
- Rooms and Equipment
- Mailing Lists
- Routes and Relays
- Mail In to a Webhook
- Outbound Shaping
- The COM API and Scripting
- Event Scripts
- The REST API
- Command Line
- APIs Reference
5. Contribute to it
- Project Handbook
- Architecture
- Contributing
- Release Process
- Governance
- Assurance Case
- Regression Test Environment
- Fuzzing
- Regulatory Scope
- Third-Party Binaries
Look it up — from any journey
- Settings Reference
- Settings Overview
- Capabilities and Configuration
- Control Panel Reference
- Control Panel Pages
- Ports Reference
- Changes-Since-6210
- Version-History-to-6210
- Glossary
About this wiki
- hMailServer 6.3.7 is the latest release (17 October 2026, schema 6108)
- Pages say since 6.3.4 where a feature is new in it
- AGPL-3.0-or-later
- Repository, the one place the project is worked on
- Its mirror on GitHub, since 18 October 2026, with no Issues
- Questions: a GitLab issue with the Question template, GitHub Discussions Q&A, or the forum
- Report a documentation error: a GitLab issue naming the page