Email Migration Guide: cPanel to Mail-in-a-Box (MiaB)
This guide outlines the step-by-step process for migrating email accounts from a cPanel hosting environment to a Mail-in-a-Box (MiaB) server. The migration process is divided into three main phases: preparation, credential migration, and email data transfer.
Table of Contents
Preparation Steps
User Communication
- Send a mass email to all account holders with:
- Notice of upcoming migration
- New webmail address
- Connection instructions for email clients (mobile/Outlook/Gmail)
- Warning not to change passwords during migration
- Adequate advance notice (recommended: several days)
Initial Setup
- Create a test email account in MiaB control panel for your domain
- This allows MiaB to configure necessary DNS records
Migrating User Credentials
Extracting Current Credentials
- Locate the credentials file on cPanel:
- Path:
etc/<domain name>/shadow - Download via SFTP
- Note down cPanel server IP address for future access
- Path:
Password Hash Verification
- Check password hashing scheme:
- If passwords start with
$6$: Compatible with MiaB’s SHA512-CRYPT - If different format: Generate temporary passwords and notify users
- If passwords start with
Database Preparation
- Access MiaB’s SQLite database:
- Location:
/home/user-data/mail/users.sqlite - Create backup before proceeding
- Location:
Setting Up Database Access
- Configure permissions if needed:
sudo gpasswd -a <username> mail sudo chmod -R g+rxw /home/user-data/mail
Importing Credentials
- Access SQLite CLI:
sudo sqlite /home/user-data/mail/users.sqlite - Import user accounts:
- Verify current records:
SELECT * FROM users; - Execute INSERT statements
- Verify successful import
- Exit with
.quit
- Verify current records:
Email Data Migration
DNS Configuration
- Update nameservers in domain registrar:
- Switch from cPanel nameservers to MiaB nameservers
- Note: This marks the transition point for email service
Mailbox Setup
- Initialize email directories:
- Send test email to verification account
- Send welcome emails to all accounts
Email Transfer
- Copy email data:
- Source:
mail/<domain name>(cPanel) - Destination:
/home/user-data/mail/mailboxes/<domain name>(MiaB) - Include all subdirectories (new, cur, .Trash, .Spam, .Sent, .Archived)
- Exclude dovecot metadata files (dovecot-*)
- Source:
Permission Configuration
- Set appropriate permissions:
sudo chmod -R g+rxw /home/user-data/mail
Post-Migration Tasks
- Verify email functionality for all accounts
- Provide support for email client configuration
- Monitor for any migration-related issues
- Document any necessary troubleshooting steps
Notes
- Consider using alternative file transfer methods if available (FTP can be slow)
- Keep original cPanel backups until migration is confirmed successful
- Plan for user support during the transition period
- Consider creating a FAQ document for common user issues
Remember to maintain backups throughout the migration process and test thoroughly before completing the final transfer.
[convert_user_accounts.php]
<?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.";
}
[extract_mail.php]
<?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);
}
}
}