Skip to content

Instantly share code, notes, and snippets.

@osiloke
Forked from alexweissman/README.md
Created November 11, 2016 22:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save osiloke/f15b89d1182551cbdf00aa0c991b2519 to your computer and use it in GitHub Desktop.
Save osiloke/f15b89d1182551cbdf00aa0c991b2519 to your computer and use it in GitHub Desktop.
Migrating email accounts from a cPanel hosting environment to Mail-in-a-Box

Migrating email accounts from a cPanel hosting environment to Mail-in-a-Box

Part 1: Pregame

  1. Send a mass email to all of your account holders, letting them know that you will be migrating their email accounts to a new server. Send them the instructions from MiaB control panel for connecting to your MiaB server from their mobile/Outlook/Gmail/etc, if applicable. Also, send them a link to the new webmail address. Be sure to give adequate advanced notice (several days, if possible). Advise them to not change their passwords during this time (their passwords will be preserved during migration).
  2. Create a new "test" email account in the MiaB control panel for your domain. This will let MiaB set up the DNS records needed for the domain.

Part 2: Copy credentials

Copy the email account credentials from your cPanel host to MiaB:

  1. In a typical cPanel hosting environment, they'll be stored in your user directory in a file: etc/<domain name>/shadow. Download this file via SFTP. This file is a plaintext file, and consists of column values username, password_hash, and some other things, separated by :. You may also want to get the IP address of your cPanel server (if you don't already have it noted down). Once you switch over your domain nameservers, you'll need the IP address to connect to your old cPanel account.
  2. The important thing here is to make sure that the hashing scheme for your passwords in this file is consistent with the hashing scheme used by MiaB. If the passwords start with the characters $6$, then they are being hashed using SHA512-CRYPT, which is what MiaB uses. If the passwords do not begin with $6$, you may not be able to preserve your users' passwords (sorry). In this case, I recommend generating individual temporary passwords for them (which you must send to them in plaintext :(), and then modifying the script below to hash them with SHA512-CRYPT.
  3. MiaB uses SQLite to store user account credentials. We will convert the shadow file into a series of INSERT statements which we can execute from your new server's shell to add the accounts to the database (you can download the PHP script below and run it from the command line).
  4. Your user database on the MiaB server is located in /home/user-data/mail/users.sqlite. Make a backup of this file (again over SFTP) before you proceed.
  5. If you can't see/access the DB file over FTP, you may need to give yourself permissions. MiaB has set the owner for most things to user mail, with a group owner also mail. The easiest thing I've found, is to go into shell and add myself to the mail group:

sudo gpasswd -a <username> mail

And then give the mail group read,write,execute permissions on the necessary directories:

sudo chmod -R g+rxw /home/user-data/mail

You can revoke these permissions later, if you are concerned about the security implications.

Once you've backed up the users.sqlite file and have generated the INSERT statement, you can go ahead and update the database on the server.

  • To access the SQLite CLI, you'll enter sudo sqlite /home/user-data/mail/users.sqlite. You'll then get a shell prompt.
  • To see the current records in the DB, if any, simply enter SELECT * FROM users;.
  • To add your user accounts from the old database, copy-paste the entire INSERT statement generated by the script below. If it is too long, feel free to break it up into chunks.
  • Run SELECT * FROM users; again to confirm that the accounts have been added.
  • To exit the SQLite CLI, simply enter .quit.
  • Congratulations, the account credentials have been successfully migrated. But, there is still more to do!

Part 3: Migration

  1. When the notice period has ended, you can redirect the nameservers. In your domain registrar's control panel, change the nameservers from those of your cpanel host to your MiaB nameservers. This is the point at which your account holders will no longer be able to connect to the old mail server.
  2. Send an email from (from anywhere) to the test account you created in step 2. This will allow MiaB to create the directory for the domain's email.
  3. Send test/welcome emails to each account. This will allow MiaB to create the individual mailbox directories for each user.
  4. Copy the emails only (usually files with very long, random names) from all subdirectories in each user directory on the shared hosting account, to the corresponding subdirectories on the MiaB server. In cPanel, the user directories are usually found in mail/<domain name>. In MiaB, they should be found in /home/user-data/mail/mailboxes/<domain name>.
  5. This can be tricky, because each user may have many subdirectories (new, cur, .Trash, .Spam, .Sent, .Archived, etc), and we need to copy the emails without copying the dovecot metadata (dovecot-* files). My strategy was to download the entire domain directory (mail/<domain name>) from the old server, and then run the script extract_mail.php to move all the email-containing directories to a separate location. Then, I simply upload this filtered directory to the new server, which automatically merges the files into the server's own directory structure.
  6. If you do this over FTP, you will likely need to give yourself the necessary permissions to the newly created user directories. Again, you can do this with sudo chmod -R g+rxw /home/user-data/mail. Copying all the files may take some time, especially over FTP. If you have a faster alternative method for downloading files from your cPanel account, you should use that instead.
  7. You should be good to go! You'll probably get a slew of emails from users who need help configuring their mail clients for the new server. Sorry, 'tis the life of a sysadmin.
<?php
// The path to your shadow file, which contains the old password database
$path = "example.com/shadow";
// The domain portion of your email accounts
$domain = "example.com";
$fp = fopen($path, "r");
if ($fp) {
$rows = array();
while (($line = fgets($fp)) !== false) {
// columns in shadow file are (id, username, password_hash, some number, ...)
$columns = explode(":", $line);
// Columns in SQLite DB are (id, email, password, extra, privileges). So, we need to do some conversion here.
$rows[] = "\n(NULL, \"{$columns[0]}@$domain\", \"{SHA512-CRYPT}{$columns[1]}\", \"\", \"\")";
}
fclose($fp);
$query = "INSERT INTO users (id, email, password, extra, privileges) VALUES " .
implode(",", $rows) . ";";
echo $query;
} else {
echo "File '$path' not found.";
}
<?php
$path = "example.com";
foreach (glob("$path/*", GLOB_ONLYDIR) as $dir) {
// Move regular subdirectories
foreach (glob("$dir/*", GLOB_ONLYDIR) as $subdir) {
$target = __DIR__ . "/extracted/$subdir";
if (!is_dir($target)) {
mkdir($target, 0777, true);
}
$source = __DIR__ . "/$subdir";
echo "Moving $source to $target\n";
rename($source , $target);
}
// Move directories inside hidden subdirectories too
foreach (glob("$dir/.*", GLOB_ONLYDIR) as $hiddendir) {
if ($hiddendir == "$dir/." || $hiddendir == "$dir/..")
continue;
foreach (glob("$hiddendir/*", GLOB_ONLYDIR) as $subdir) {
$target = __DIR__ . "/extracted/$subdir";
if (!is_dir($target)) {
mkdir($target, 0777, true);
}
$source = __DIR__ . "/$subdir";
echo "Moving $source to $target\n";
rename($source, $target);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment