---
title: "Mailcow — Maildir Import via rsync + doveadm"
aliases: [mailcow-import, mailcow-maildir, mailcow-doveadm, mailcow-email-import]
tags: [mailcow, email, maildir, dovecot, docker, selfhosted]
sources:
  - "daily/2026-04-16.md"
created: 2026-04-16
updated: 2026-04-16
---

# Mailcow — Maildir Import via rsync + doveadm

Importing email into Mailcow (the Docker-based mail server) requires copying Maildir files to the correct Docker volume path, fixing ownership, and running `doveadm index` — without the indexing step, mail clients will not see the imported messages even though they exist on disk.

## Key Points

- Mailcow stores mail in a Docker named volume: `/var/lib/docker/volumes/mailcowdockerized_vmail-vol-1/_data/{domain}/{user}/Maildir/`
- The volume is owned by the `vmail` user with **uid/gid 5000** — files must be chowned after rsync
- **`doveadm index` is mandatory** after copying — without it, Dovecot's index doesn't know about the new files and IMAP clients see nothing
- Always make a backup of the existing Maildir before importing: copy to `{user}.backup.YYYY-MM-DD` on the server
- Merge strategy: shared mailbox messages can go directly into the primary user's Inbox without subfolders

## Details

### Volume Path

```
/var/lib/docker/volumes/
  mailcowdockerized_vmail-vol-1/
    _data/
      {domain}/           e.g. ai-impress.com
        {user}/           e.g. v.samoilenko
          Maildir/
            cur/          delivered/read messages
            new/          newly delivered messages
            tmp/          temporary storage
```

The path is `{domain}/{user}` not `{user}@{domain}`.

### Import Procedure

```bash
# 1. Back up the existing mailbox
MAILDIR="/var/lib/docker/volumes/mailcowdockerized_vmail-vol-1/_data/ai-impress.com/v.samoilenko"
cp -r "$MAILDIR/Maildir" "$MAILDIR/../v.samoilenko.backup.$(date +%Y-%m-%d)"

# 2. Copy downloaded EML files into Maildir/new/ (rsync preserves timestamps)
rsync -avz ./downloaded-mail/ "$MAILDIR/Maildir/new/"

# 3. Fix ownership — vmail user owns the volume (uid/gid 5000)
chown -R 5000:5000 "$MAILDIR/Maildir/"

# 4. Tell Dovecot to index the new files (runs inside the dovecot container)
docker exec mailcowdockerized-dovecot-mailcow-1 \
    doveadm index -u v.samoilenko@ai-impress.com '*'
```

The `'*'` glob means index all folders. For a single folder: `'INBOX'`.

### Why doveadm index Is Required

Dovecot maintains its own metadata index (`.dovecot.index`, `.dovecot.index.cache`) alongside the Maildir files. When files are added externally (not delivered through Dovecot's own mail delivery path), Dovecot has no record of them. IMAP clients ask Dovecot — not the filesystem — for the message list. Without indexing, `SELECT INBOX` shows an empty folder even though `cur/` contains thousands of EML files.

### Verifying the Import

```bash
# Count messages Dovecot can see (must match what you imported)
docker exec mailcowdockerized-dovecot-mailcow-1 \
    doveadm fetch -u v.samoilenko@ai-impress.com 'mailbox INBOX' uid | wc -l

# Or use Mailcow webmail (SOGo) — it queries Dovecot directly
```

### Merging Shared Mailboxes into Inbox

When merging multiple source mailboxes into a single user's Inbox (without creating subfolders), place all downloaded EML files into `Maildir/new/` before running `doveadm index`. Dovecot will move them to `cur/` during indexing. The merge produces a flat Inbox — no folder hierarchy.

## Related Concepts

- [[wiki/concepts/microsoft-graph-api-mailbox-migration]] — how to download the EML files from Microsoft 365 before this import step
- [[wiki/homelab/_index]] — Mailcow runs on self-hosted Proxmox infrastructure
- [[wiki/connections/graph-api-vs-msal-app-vs-delegated]] — auth context for the source (M365) side of the migration

## Sources

- [[daily/2026-04-16.md]] — ai-impress.com email migration from M365 to Mailcow; primary mailbox 2713 msgs + 8 shared mailboxes 539 msgs → 2956 msgs in single Inbox; backup created as `v.samoilenko.backup.2026-04-16`
