Skip to content
  • Categories
  • Recent
  • Popular
  • Tags
  • Users
  • Groups
  • Documentation
  • Downloads
  • Report a bug
  • GitHub mirror
  • Paid support
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
hMailServer Community Forum
hMailServer 6.3.8 is the current release, signed 2 November 2026. Windows and Linux, and an in-place upgrade from 5.3 or later, but for the original hMailServer's 5.7.Download 6.3.8 Documentation FAQ
  1. Support and discussion for hMailServer
  2. Running hMailServer
  3. Installation, migration & upgrades
  4. Bringing mailboxes in: IMAP mirror, Google, Microsoft 365, mbox, Maildir and PST

Bringing mailboxes in: IMAP mirror, Google, Microsoft 365, mbox, Maildir and PST

Scheduled Pinned Locked Moved Installation, migration & upgrades
migrationimapwebmailcontrol-deckrest-api
1 Posts 1 Posters 141 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • ProgressiverobotP
    ProgressiverobotP
    Progressiverobot
    hMailServer Team
    wrote on last edited by chris
    #1

    Written for 6.3.4. hMailServer 6.3.7 (17 October 2026) has the migrations as a card on the Control Panel's Backup, restore & migration page, where this topic says there is no Control Panel page; and a message collected from an external account is sent to SpamAssassin with the Return-Path the other server recorded, where it was the guess from the From field, so its SPF and envelope rules may score such mail differently. See the 6.3.7 announcement. The Windows installer of hMailServer 6.3.8 (2 November 2026) refuses an installation of the original hMailServer's 5.7 (5.7.0, its pre-release builds 2788 and 2843, 5.7.1 and 5.7.2), which this fork's upgrade chain has no step from, before it changes anything, and the installers of 6.3.7 and earlier must never be run over one: such a server's mail comes in by a migration of kind imap, as Migration.md's From the original hMailServer says. See the 6.3.8 announcement.

    This topic covers every route 6.3.4 offers for bringing existing mail into this server: the webmail's Other accounts page for one person, an external account with the mirror on for a few mailboxes that must stay in step, migration jobs for hundreds of mailboxes from an IMAP server, Google Workspace or Microsoft 365, the Import Tool for mbox files and a Maildir, and the PST import for Outlook data files. It ends with the mailbox move, for a mailbox that is already here and needs a new address or a new domain. The one thing to know first: every route needs the local account to exist. Create the accounts with the Import Tool's text-file import, POST /api/v1/domains/{domain}/accounts, a spreadsheet over REST and hmctl, or SCIM, and only then bring the mail. Moving an installation is a different subject: Upgrading to 6.3.4 for an upgrade and Moving to new hardware for a new machine.

    Which route

    You are moving Use Keeps Does not keep
    One person's own mailbox, by that person The webmail's Other accounts (since 6.3.4) Folders as copies, then new mail collected Rules, signatures
    A few mailboxes that must stay in step until the cut-over An external account with Mirror every folder on (6.3.3 and later) Folders, every message byte for byte, the five standard flags, the internal date Subscriptions, custom keywords, ACLs
    Many mailboxes from an IMAP server, Google Workspace or Microsoft 365 A migration, a job per mailbox (since 6.3.4, schema 6090) The above, with keywords, special-use folders, contacts and calendars Rules, signatures, shared mailboxes, ACLs, Gmail's labels as labels
    mbox files The Import Tool, one folder per file (Windows only) Every message, the date from the headers Flags
    A Maildir The Import Tool's Select Maildir (Windows only) The Maildir++ hierarchy, the flags in the file names Custom keywords
    Outlook PST files PST import, a migration of kind pst (since 6.3.4) Folders, messages rebuilt as Internet mail, contacts, calendar items, tasks Attachments by reference, OLE objects, distribution lists
    What PST import refuses Outlook itself, over IMAP Whatever Outlook uploads Anything Outlook does not put on the wire

    One person, from the webmail: Other accounts

    Since 6.3.4. Settings, Other accounts lets a person do the IMAP route for their own mailbox without an administrator. They pick the old provider (Gmail, Outlook.com, Yahoo Mail and iCloud Mail fill in the server, port and encryption), give the user name and password, choose whether to leave the mail there, and tick Bring the folders over too. It is an external account made through /api/v1/me/fetch-accounts, with these differences from one an administrator makes:

    • The spam and virus filters are on for new mail; folders brought over arrive as copies, without the filters.
    • The host must resolve to public addresses only, on port 110 or 995 (POP3) or 143 or 993 (IMAP), unless the administrator turns on reader_fetch_accounts_private_addresses. Schema 6104 marks such an account reader_created, and the host is judged again at every collection: a name that answers a private address later is not collected, and the error log says why (HM5909).
    • The interval is at least 15 minutes, and a person has at most reader_fetch_accounts_max of them: 3 by default, and 0 takes the page away.
    • A host on FetchOAuth2Hosts (outlook.office365.com by default) is refused from the page; only a server administrator adds one.

    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 the server with Google and Microsoft, the page offers Sign in to Gmail and Sign in to Outlook.com: the person grants IMAP access there and the 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 set on PUT /api/v1/settings: import_oauth_redirect_base_url (the redirect URI to register is that plus /portal/oauth/callback), import_oauth_google_client_id and import_oauth_google_client_secret, import_oauth_microsoft_client_id and import_oauth_microsoft_client_secret. The Google client needs the Gmail API and the https://mail.google.com/ scope; the Microsoft Entra registration needs the delegated IMAP.AccessAsUser.All and offline_access permissions. Until Google verifies the app, only the test users named on its consent screen can sign in.

    A few mailboxes that must stay in step: the mirror

    With Mirror every folder on, the server's own IMAP client does what imapsync does. The switch is on the account dialog's External tab in the Control Panel (Windows) and on the Deck's fetch-accounts view; over COM (Windows) it is FetchAccount.ServerType = 1 and FetchAccount.MirrorFolders = true.

    1. Create the local account.
    2. Add an external account on it: server type IMAP, the remote host, port and security (implicit TLS on 993, STARTTLS on 143), the remote credentials, and the mirror on.
    3. Decide what happens on the far side. Days to keep messages at 0 deletes each message from the remote folder once it is filed here; any other value leaves it there, so the two servers stay in step for as long as the account polls. A migration usually leaves the messages in place until the cut-over, then one last poll, and the account is disabled.
    4. Poll. Download now starts a collection at once. A large mailbox is collected over several polls, and a message is recorded as collected only after it has been filed.

    A mirrored message is stored byte for byte: no X-hMailServer-ExternalAccount header, no delivery, no rules, no anti-spam or anti-virus, because it is a copy of mail the other server had already accepted. The remote flags and internal date become the local ones, and Archive/2025 becomes Archive.2025.

    Use a new external account for the mirror. One that has been collecting the INBOX without the mirror collects it once more when the mirror is switched on. A \Noselect mailbox is skipped with a line in the application log, OnExternalAccountDownload does not fire for a mirrored message, and subscriptions, ACLs, quotas, Sieve and vacation settings on the far side are not read.

    Many mailboxes: migration jobs

    Since 6.3.4, schema 6090. A migration is a batch the server runs itself: a job per mailbox, throttled, resumed after a failure or a restart, with a report per mailbox and the contacts and calendars beside the mail. It is administered under /api/v1/migrations and in the Control Deck's Migrations view; there is no COM interface, and in 6.3.4 no Control Panel page (in 6.3.7's Control Panel the migrations are a card on Backup, restore & migration).

    A migration names its source: kind imap (a password per mailbox), google or microsoft365 (each mailbox signed in to by its owner), or pst; concurrency (1 to 32, 4 by default); and messages_per_minute (0 for no limit). A Google or Microsoft 365 migration reads imap.gmail.com or outlook.office365.com on port 993 over TLS, and any other host is refused. A job is queued, running, paused, done, failed or cancelled, through the phases mail, contacts, calendars and report.

    POST /api/v1/migrations               {"name": "Old server", "host": "imap.old.example"}
    POST /api/v1/migrations/{id}/jobs     the CSV below, or one job as JSON
    POST /api/v1/migrations/{id}/start
    GET  /api/v1/migrations/{id}/jobs/{job}/report
    GET  /api/v1/migrations/{id}/summary.csv
    
    sourceuser,secret,target
    [email protected],Anna's old password,[email protected]
    [email protected],,[email protected]
    

    One request takes up to 5,000 lines. Every line is checked before any job is made, and a bad line refuses the whole request and names itself, so nothing is half added. A job into an account another migration is copying into now is refused (409).

    Google Workspace and Microsoft 365. A job added with an empty secret waits for its owner: the answer carries signin_url, a one-use link for that person to open, sign in as that mailbox and grant access. A sign-in as anybody else attaches nothing, and POST .../jobs/{job}/signin makes a new link. The scopes asked for are Google's https://mail.google.com/, https://www.googleapis.com/auth/carddav and https://www.googleapis.com/auth/calendar, and Microsoft's https://outlook.office.com/IMAP.AccessAsUser.All and offline_access with Microsoft Graph Contacts.Read and Calendars.Read. A work or school tenant may need an administrator's consent.

    What a job does. It maps 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, and everything else to the same path. It opens each folder with EXAMINE, so nothing on the source is marked read, and stores each message byte for byte with its flags, keywords and internal date. A message too large is skipped as too_large; an account over its quota pauses the job. No rule, filter or scan runs over a copied message. Contacts and calendars follow: 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. A job is one copy, not a synchronisation: move the MX records first and migrate after, or keep a mirror for the mailboxes that must stay in step.

    It survives being interrupted. After every 50 messages and at the end of each folder the job writes its resume marks, and a job that has run before reads back what it wrote, so each message arrives once. A failure time may mend is retried after 1, 5 and 15 minutes and then hourly; after 24 attempts in a row without a message copied the job is failed. Wrong credentials fail it at once, and POST .../jobs/{job}/retry with {"secret": "..."} takes a mended password.

    Throttling is threefold: concurrency per migration; MigrationConnectionsPerHost (4 by default, 1 to 64) across every migration from one source host, because a provider counts sessions per client address; and at most 64 jobs on the server at once.

    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, never a secret's value. Jobs are not carried by a backup. HM7240 (a resume mark could not be written) and HM7241 (a message could not be filed) are the two codes that reach the error log for a job from an IMAP server, Google or Microsoft 365. A PST job says the same two as HM7370 and HM7371, and its contacts and calendars phases add HM7410 and HM7411.

    The report 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.

    mbox files, a Maildir and accounts from a text file: the Import Tool

    The Import Tool is a Windows program (Start menu > hMailServer > Import Tool, or Addons\ImportTool\ImportTool.exe) that works through COM, each message going to the server through Utilities.ImportMessageFromFileToIMAPFolder; there is no Import Tool on Linux. It imports a folder of mbox files into one account, one IMAP folder per file; Inbox in any case is the INBOX, and a subfolder's files are a second run. Each message is dated from its Received or Date header. mbox carries no flags the tool could read, so every imported message is unread.

    Select Maildir points at the directory holding cur, new and tmp, and lists the INBOX and every Maildir++ folder beside it. The flags after :2, in a file name are set on the copy: S seen, F flagged, R answered, D draft, T deleted. A colon is not allowed in a Windows file name, so the tool also reads ;2, and the same marker written with an exclamation mark in place of the colon; a copy whose names lost the info part imports unread.

    Accounts from a text file. The tool's other button creates or updates the accounts of one domain from a comma-separated text file, three fields a line: the account's name without the domain, its password and its size limit in MB (0 for none). Where the breach check is on, it runs for each password the tool sets through COM's Account.Password, one request per account: run a large import against your own mirror of the endpoint, or with the check off.

    Outlook data files: PST import

    Since 6.3.4. The server reads a PST itself, with a reader of this project's own written from Microsoft's published specifications and no third-party PST code. It is a migration of kind pst: one job per file, each into one account.

    Off until a directory is named. A job names a file, never a path, and the file is looked for only in the subdirectory named for the target account's domain inside the directory pst_import_directory names (PstImportDirectory in hm_settings, set with PUT /api/v1/settings or on the 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 [email protected] names archive.pst
    
    1. Copy the file into the domain's subdirectory, where the service's account can read it. A share on another machine is refused, and so is a name that climbs out of the domain's directory.
    2. Make the migration, POST /api/v1/migrations with {"name": "Archives", "kind": "pst"}, then jobs as CSV lines of file,password,target over REST or in the Deck, or one job as JSON with hmctl api POST /api/v1/migrations/{id}/jobs. There is no Import Tool button for it and no COM route.
    3. Start it. It needs manage_accounts and manage_mailbox in the target's domain.

    What comes in. The folders a person sees in Outlook, with Sent Items, Deleted Items, Drafts and Junk E-mail found by what the store says they are, never by their names. Every message is rebuilt as Internet mail, deterministically, so a resumed job knows what it filed. Read, unsent, flagged and replied state become \Seen, \Draft, \Flagged and \Answered, forwarded the keyword $Forwarded, categories keywords. Contacts go into the address book, calendar items and tasks into the calendars, notes and journal entries into mail folders as messages. ANSI files (Outlook 97 to 2002) are read.

    What it refuses, with a sentence saying what to do: the 4K-page layout Outlook 2013 and later write for an OST, an OST caching an Exchange mailbox, a file under Windows Information Protection, and a missing or wrong password. A file Outlook still has open pauses the job. A message over 128 MB of text and data together is left out and named. Migration.md is candid about its evidence: no password-protected PST and no OST from Outlook were at hand.

    The reader runs in a process of its own (hMailServer.exe --pst-read on Windows, hmailserver --pst-read on Linux, not a command for an administrator), killed on a pause, a cancel or a stop, or when it has not answered in ten minutes. A file that crashes it costs one message, not the service. This is crash containment, not a sandbox: the reader runs as the service's own account, bounded in memory (2 GB committed on Windows, 4 GB of address space on Linux). The fixture API.PstImport runs on Windows; nothing runs it on Linux yet.

    What is not migrated

    • Rules and filters, signatures, out-of-office replies and forwarding: make them again here.
    • Shared mailboxes and permissions; 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. A google migration copies each message once, and the star arrives as \Flagged.
    • Contact groups; from Microsoft 365, the default contacts folder and calendar only.

    A mailbox already here: renaming it, or moving it to another domain

    Do not copy it into a second account: that loses everything hanging off the account id, which is its rules, folders, application passwords, second factor, contacts, calendars and role. Move or rename (since 6.3.4) keeps the account's row, and leaves the old address as an alias unless you say otherwise. Relocating an installation, and moving or renaming a mailbox has where it is done, what moves and what is refused.

    Where to read more

    • The wiki page: Migration
    • The document, with every field, limit and refusal: Migration.md
    • Renaming and moving a mailbox: MailboxMove.md
    • The documentation page: Importing accounts and mail, the Import Tool
    • On this forum: The Control Deck, where the Migrations view is, and The webmail portal at /portal, where Other accounts is.
    1 Reply Last reply
    0

    Hello! It looks like you're interested in this conversation, but you don't have an account yet.

    Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

    With your input, this post could be even better 💗

    Register Login
    Reply
    • Reply as topic
    Log in to reply
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes


    hMailServer Community

    The community support forum for hMailServer — the free, open-source mail server for Windows and Linux — maintained by Progressive Robot Ltd. The software is AGPL-3.0 and stays that way; this is where it is discussed, debugged and documented.

    The software

    • Documentation
    • Downloads
    • hMailServer 6.3
    • Source on GitLab

    Getting help

    • Forum rules
    • About this forum
    • Support plans
    • Pay monthly support
    • Talk to Progressive Robot

    Legal

    • Privacy policy
    • Terms and conditions
    • Cookie policy

    Progressive Robot Ltd · 220 Chester Business Park, Heronsway, Chester, Cheshire CH4 9GB, United Kingdom · +44 (0)1244 911212 · [email protected] · VAT 506152326

    Powered by NodeBB

    • Login

    • Don't have an account? Register

    • Login or register to search.
    • First post
      Last post
    0
    • Categories
    • Recent
    • Popular
    • Tags
    • Users
    • Groups
    • Documentation
    • Downloads
    • Report a bug
    • GitHub mirror
    • Paid support