Maildir to zmmailbox with bash

The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

What's new

I decided to rewrite Jarosław's script to fix a few bugs I stumbled upon while migrating my bare-Postfix server to Zimbra, namely:

  • all folders were merged into the main folder due to a bug in the script (hint: '=' instead of '==').
  • folders with spaces in their name were not imported and caused an error
  • import messages from accounts across multiple domains, if needed
  • made the code readable
  • no need for two loops


How to use

The script expects to find the mailboxes in the current path! The structure of maildirs must be as follows:

domain/username/{cur|new|tmp}
domain/username/subfolder1/{cur|new|tmp}
domain/username/subfolder2/{cur|new|tmp}
...

After the script has run, every zimbra user will have a subfolder in his mailbox called 'old-mbox' (feel free to change the name at the beginning of the script). The hierarchy of subfolders is maintained under old-mbox.

The code

#!/bin/bash

# Postfix virtual transport -> Zimbra mailbox migration
# written by NERvOus (http://www.nervous.it) - 2009-12-25
# minor fixes by NERvOus (http://www.nervous.it) - 2013-07-23

# base folder where msgs will be imported
BFOLDER="old-mbox"
ZMMBOX="/opt/zimbra/bin/zmmailbox"
BDIR=$(pwd)

echo You must run $0 from inside /var/mail/virtual directory
echo $0 expects to find the mailboxes in the current path!
echo The structure of maildirs must be as follows:
echo 
echo "domain/username/{cur|new|tmp}"
echo "domain/username/subfolder1/{cur|new|tmp}"
echo "domain/username/subfolder2/{cur|new|tmp}"
echo ...
echo 
echo All folders will be stored in a subfolder called $BFOLDER
echo The hierarchy of subfolders will be maintained under $BFOLDER.
echo 
echo Press Enter to start, CTRL+C to abort.
read

# handle folders with a space inside, they are more common than you may
# think
IFS='
'

for p in $(find . -type d -name cur); do
        DOMAIN=`echo $p | cut -d'/' -f2`
        UNAME=`echo $p | cut -d'/' -f3`
        DIRNAME=`echo $p | cut -d'/' -f4`
        # this may fail, if folder already exists. Who cares. Ignore the
        # error.
        echo createFolder /$BFOLDER | $ZMMBOX -z -m $UNAME@$DOMAIN
        if [ "$DIRNAME" == "cur" ]; then
                echo Importing INBOX folder for $UNAME@$DOMAIN from $BDIR/$DOMAIN/$UNAME/ 1>&2
                # we are importing the top level folder
                echo addMessage --noValidation /$BFOLDER $BDIR/$DOMAIN/$UNAME/cur | $ZMMBOX -z -m $UNAME@$DOMAIN
                echo addMessage --noValidation /$BFOLDER $BDIR/$DOMAIN/$UNAME/new | $ZMMBOX -z -m $UNAME@$DOMAIN
        else
                DIRNAME=$(echo $DIRNAME | sed -e 's/\/cur$//')
                echo Importing folder $DIRNAME for $UNAME@$DOMAIN from $BDIR/$DOMAIN/$UNAME/$DIRNAME 1>&2
                echo createFolder \'/$BFOLDER/$DIRNAME\' | $ZMMBOX -z -m $UNAME@$DOMAIN
                echo addMessage --noValidation \'/$BFOLDER/$DIRNAME\' \'$BDIR/$DOMAIN/$UNAME/$DIRNAME/cur\' | $ZMMBOX -z -m $UNAME@$DOMAIN
                echo addMessage --noValidation \'/$BFOLDER/$DIRNAME\' \'$BDIR/$DOMAIN/$UNAME/$DIRNAME/new\' | $ZMMBOX -z -m $UNAME@$DOMAIN
        fi
done


Jump to: navigation, search