Skip to content

Overview

An import reads an account from a source, over the protocol that the source offers, and records its contents in a local archive. A later export writes the archive to a JMAP server. The import and the export never communicate directly: the archive is all that passes between them.

ImporterReadsData types
JMAPA JMAP serverEvery type the server advertises
IMAPAn IMAP serverMail
CalDAVA CalDAV serverCalendars, events, tasks and notes
CardDAVA CardDAV serverAddress books and contacts
WebDAVA WebDAV file collectionFiles
ManageSieveA ManageSieve serverSieve scripts
MaildirA local Maildir++ treeMail
Google TakeoutA local directory of mbox, iCalendar and vCard filesMail, calendars and contacts
Exchange (EWS)Exchange Server or Exchange Online over EWSMail, calendars and contacts
Exchange (Graph)Microsoft 365 over Microsoft GraphMail, calendars, contacts and OneDrive files

To copy a whole account, the importers that read one data type are combined into the same archive. A typical combination is IMAP for mail, CalDAV and CardDAV for calendars and contacts, and ManageSieve for filters.

Source systemImporters
StalwartJMAP. When the source does not advertise the capability for files, contacts or calendars, WebDAV, CardDAV or CalDAV for that data type, as described under Checking a Stalwart source.
Another JMAP server, such as FastmailJMAP
DovecotIMAP with a master user, and ManageSieve; CalDAV and CardDAV when the deployment runs a calendar and contacts server such as SOGo, Radicale or Baikal
Cyrus IMAP, Courier and other IMAP serversIMAP, plus ManageSieve where the server offers it
Google Workspace and GmailIMAP, CalDAV and CardDAV, or Google Takeout for a one-time copy
Microsoft 365Exchange (Graph), or Exchange (EWS) while Microsoft allows it
Exchange Server on premisesExchange (EWS)
A Maildir tree on diskMaildir

The migration as a whole is described in Migrating from hosted services for a hosted service, and in the migration guide for a self-hosted server.

An import does not copy blindly. It compares the objects that the source currently holds with those already in the archive, and acts on the difference:

  • It reads and stores the objects that are new.
  • It refreshes the objects that changed, where the source protocol shows changes.
  • It removes from the archive the objects that disappeared from the source.

Containers (mailboxes, calendars, address books, file folders) are processed before the objects they contain. The importer pages describe how each importer detects changes, and the exceptions: the Takeout importer never removes objects, and the Graph importer does not refresh objects already in the archive.

An import can therefore be interrupted and started again: the repeated run compares again, and continues. A run repeated later against the same account copies what changed in the meantime.

The archive is the last positional argument, and is created when it does not exist. Credentials are given through environment variables or a prompt, as described under Credentials.

An object that cannot be parsed, such as a malformed calendar entry, is skipped with a warning and counted towards the partial failure exit code. The rest of the run continues. --dry-run reports what the import would do without writing to the archive, as described under Dry runs.

An archive records the identity of each source it was filled from, such as the URL and the account for a JMAP source, the server and the login for IMAP, or the path for Maildir and Takeout.

A later import of the same kind from a different source into the same archive is refused with exit code 4, which keeps two unrelated accounts from being mixed in one file. The message names the recorded source, for example archive already records JMAP source (<url>, account <id>); pass --allow-source-change to import a different account. Sources of different kinds do not conflict, so an IMAP and a CalDAV import of the same account fill one archive.

--allow-source-change lets the import proceed, and records the new source next to the old one. The objects read from the old source stay in the archive.

The identity is compared as given. For JMAP, for example, switching --url between a base URL and the session URL of the same server counts as a different source.