05 Sep

moving email from qmail to postfixadmin

Yesterday we had to move about 300 domains from one machine to another. We bought a new machine recently and are taking this opportunity to move from Qmail (difficult to use, in my opinion) towards Postfix.

After doing one or two by hand, i decided that’s stupid – why not just automate the whole thing.

So I whipped up a script that reads details from vqadmin and uses those details to create postfix emails using mailadmin.

Please note that this does not handle forwards and other weirdness – just plain old email accounts. After running it, you need to check the accounts for forwards. I /could/ adapt it, but am too lazy.

<?php

$vqadmin_url='http://1.2.3.4/cgi-bin/vqadmin/vqadmin.cgi';
$vqadmin_auth='username:password';
$postfixmailadmin_url='http://5.6.7.8/mailadmin/';
$postfixmailadmin_username='your@email.address';
$postfixmailadmin_password='password';

ob_start();

// { get all domains
	$ch=curl_init($vqadmin_url);
	curl_setopt($ch, CURLOPT_USERPWD,$vqadmin_auth);
	curl_setopt($ch, CURLOPT_POST, true );
	curl_setopt($ch, CURLOPT_POSTFIELDS, 'nav=list_domains' );
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true );
	curl_exec($ch);
	$page=join('',explode("\n",curl_multi_getcontent($ch)));
	preg_match_all('#<a href=vqadmin.cgi\?nav=view_domain&dname=([^>]*)>[^<]*</a>#',$page,$domains);
	curl_close($ch);
// }

$numdomains=0; $numemails=0;
foreach($domains[1] as $domain){
	$numdomains++;
	echo '<h2>'.$numdomains.' - '.$domain.'</h2>';
	// { get password page
		$ch=curl_init($vqadmin_url);
		curl_setopt($ch, CURLOPT_USERPWD,$vqadmin_auth);
		curl_setopt($ch, CURLOPT_POST, true );
		curl_setopt($ch, CURLOPT_POSTFIELDS, 'dname='.$domain.'&Submit=Show Users&nav=show_users' );
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true );
		curl_exec($ch);
		$page=join('',explode("\n",curl_multi_getcontent($ch)));
		curl_close($ch);
	// }
	// { extract passwords
		preg_match_all('#<tr><td><FONT face=Verdana color="\#FFFFFF"><a href=[^>]*>[^<]*</a></FONT></td><td align=middle><FONT face=Verdana color="\#FFFFFF">[^<]*</FONT></td><td align=middle><FONT face=Verdana color="\#FFFFFF">[^<]*</FONT></td><td align=middle><FONT face=Verdana color="\#FFFFFF">[^<]*</FONT></td><td align=middle><FONT face=Verdana color="\#FFFFFF">[^<]*</FONT></td><td align=middle><FONT face=Verdana color=\#FFFFFF>(<B>)?[^<]*(</B>)?</FONT></td><td align=middle><FONT face=Verdana color=\#FFFFFF>[^<]*</font></td></tr>#',$page,$matches);
		$matches=$matches[0];
		$emails=array();
		foreach($matches as $match){
			$username=preg_replace('#<tr><td><FONT face=Verdana color="\#FFFFFF"><a href=[^>]*>([^<]*)<.*#','$1',$match);
			$password=preg_replace('#<tr><td><FONT face=Verdana color="\#FFFFFF"><a href=[^>]*>[^<]*</a></FONT></td><td align=middle><FONT face=Verdana color="\#FFFFFF">([^<]*)<.*#','$1',$match);
			$emails[]=array('username'=>$username,'password'=>$password);
		}
	// }
	// { log into postfix mailadmin
		$ch=curl_init($postfixmailadmin_url.'login.php');
		curl_setopt($ch, CURLOPT_POST, true );
		curl_setopt($ch, CURLOPT_POSTFIELDS, 'fUsername='.$postfixmailadmin_username.'&fPassword='.urlencode($postfixmailadmin_password).'&lang=en&submit=Login');
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true );
		curl_setopt($ch, CURLOPT_AUTOREFERER, true );
		curl_setopt($ch, CURLOPT_COOKIEJAR, 'tmp/cookies.txt');
		curl_exec($ch);
		curl_close($ch);
	// }
	// { create domain
		$ch=curl_init($postfixmailadmin_url.'create-domain.php');
		curl_setopt($ch, CURLOPT_COOKIEFILE, 'tmp/cookies.txt');
		curl_setopt($ch, CURLOPT_POST, true );
		curl_setopt($ch, CURLOPT_POSTFIELDS, 'fDomain='.$domain.'&fAliases=25&fMailboxes=25&submit=Add Domain');
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true );
		curl_exec($ch);
		curl_close($ch);
	// }
	// { create email accounts
		foreach($emails as $email){
			$ch=curl_init($postfixmailadmin_url.'create-mailbox.php');
			curl_setopt($ch, CURLOPT_COOKIEFILE, 'tmp/cookies.txt');
			curl_setopt($ch, CURLOPT_POST, true );
			curl_setopt($ch, CURLOPT_POSTFIELDS, 'fDomain='.$domain.'&fUsername='.$email['username'].'&fPassword='.$email['password'].'&fPassword2='.$email['password'].'&fActive=on&fMail=on&submit=Add Mailbox');
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, true );
			curl_exec($ch);
			$numemails++;
			echo $numemails.':'.$email['username'].'@'.$domain.' ';
			curl_close($ch);
		}
	// }
	flush();
	ob_flush();
}

Make sure to up the timeout length of your PHP scripts – it took me about 10 minutes to transfer 1607 emails.

Also, be aware that this does not transfer the /contents/ of the email accounts – just recreates them on the other server – I don’t even want to touch that particular problem…