職場内のメール環境変更に対する圧力を軽減するために、全ユーザについて過去メールの移行を管理者側で行うことにしました。これはその時に使ったスクリプトです。ドメイン名等は変えてあります。
本スクリプトを流した後、Gmail の管理画面から IMAP による一括移行を行います。
なお、php 標準の IMAP 関数を使おうとするとc クライアントライブラリがインストールされていることだの--with-imap[=DIR] を指定して PHP をコンパイルする必要があるだのという前提事項が必要ですが、PEAR::IMAP ライブラリを使えばこれらが不要なので楽です。
#!/usr/bin/php
<?php
//
// gmail-migrate.php 2011.02.08 by M.Hotta
// 過去メールを Gmail に移行する準備を行う
//
// 使用法 gmail-migrate.php < XXXX.csv(書式:id,id,pass)
//
// 前提:
// 1.本スクリプトは現行 IMAP サーバとは別に建ててある Gmail 移行用
// IMAP(Dovecot)サーバ上で動作する。
// 2.dovecot は(本番用ではなく)移行用の ldap を見ており、ここでは
// 全ユーザで同じパスワードを設定してある。
// 3.csv ファイルの書式は Gmail の IMAP 移行指示に従ったもの
// (ドメインの管理→高度なツール→メール (IMAP) 移行を設定)
// 処理内容:
// 指定された CSV の内容に従って、該当ユーザの
// 1.旧 LDAP の mail 属性に Gmail 転送用アドレスを追加
// 2.テストメールを送信し、Gmail へ転送されることを確認する
// 3.旧 LDAP の mail 属性を Gmail のみにする
// 4.Maildir を本番 IMAP サーバから移行用サーバにコピーする。その際、
// インデックスの不整合を防ぐために dovecot index は除外する。
// 5.移行用IMAPサーバで dovecot index を再作成する
// (Gmail の IMAP 接続テストでタイムアウトになるのを防ぐため)
//
ini_set('mbstring.internal_encoding', 'UTF-8');
require_once "Net/IMAP.php";
require_once "Net/LDAP2.php";
$official_domain = '@example.com'; // generic mail domain
$gmail_domain = '@g.example.com'; // subdomain for gmail
$mta = "ipsum.example.com"; // mail relay server
$ldap_host = "hiace.example.com";
$binddn = 'cn=Manager,dc=example,dc=com';
$bindpw = 'naisho';
$basedn = 'dc=example,dc=com';
$admin_email = "support$official_domain";
$mailbody = "/home/admin/mailbody.txt";
function cmd_exec($cmd)
{
echo $cmd."\n";
return `$cmd`;
} // cmd_exec()
$ldap_config = array(
'host' => $ldap_host,
'port' => 389,
'version' => 3,
'starttls' => false,
'binddn' => $binddn,
'bindpw' => $bindpw,
'basedn' => $basedn,
'filter' => '(objectClass=*)',
'scope' => 'sub',
);
//-----------------------
// LDAPサーバへの接続
//-----------------------
$ldap = Net_LDAP2::connect($ldap_config);
if (Net_LDAP2::isError($ldap)) {
die(sprintf("LDAP CONNECT FAILED: %s\n", $ldap->getMessage()));
}
$ldap->bind();
if (Net_LDAP2::isError($ldap)) {
die(sprintf("LDAP BIND FAILED: %s\n", $ldap->getMessage()));
}
//----------------------
// IMAPサーバへの接続
//----------------------
$imap = new Net_IMAP('localhost', 143, false);
if (PEAR::isError($imap)) {
die(sprintf("IMAP Connection FAILED: %s\n", $imap->getMessage()));
}
//-------------------------------
// 標準入力から CSV を読み込む
//-------------------------------
$start = true;
while ($line = fgets(STDIN)) {
$line = rtrim($line); // remove LineFeed
list($user,$dummy,$pass) = split(',', $line);
if ($start) {
$start = false;
if ($user != 'username') {
die(sprintf("BAD FORMAT csv file.\n"));
}
continue; // Skip header
}
//---------------------------
// uid により LDAP 検索
//---------------------------
$filter = Net_LDAP2_Filter::create('uid', 'equals', $user);
$requested_attributes = array('campuscode', 'mail', 'mailquota');
$search = $ldap->search(null, $filter,
array('attributes' => $requested_attributes));
if (Net_LDAP2::isError($search)) {
die(sprintf("LDAP search FAILED: %s\n", $search->getMessage()));
}
//----------------------------
// Gmail への転送設定を追加
//----------------------------
$entry = $search->shiftEntry();
$mail = $entry->getValue('mail');
$campus = $entry->getValue('campuscode');
$npucapamail = $entry->getValue('mailquota');
printf("Current mail value: %s\n", $mail);
$gmail = strtolower("$user$gmail_domain");
$subject = strtolower($mail);
if (preg_match("/$gmail/", $subject)) {
printf("gmail address exists. Do nothing.\n");
} else {
$new_mail = $mail . ',' . $gmail;
$result = $entry->replace(array('mail' => array($new_mail)));
if (Net_LDAP2::isError($result)) {
die(sprintf("LDAP modify FAILED: %s\n", $search->getMessage()));
}
$entry->update();
sleep(3); // wait for LDAP data propagation
}
//-----------------------------------------------
// キャンパス番号により MailBox サーバ名を決定
//-----------------------------------------------
switch ($campus) {
case '1':
$imap_server = 'presage';
break;
case '2':
$imap_server = 'cresta';
break;
default:
die(sprintf("Unknown Campus: %s\n", $campus));
}
//----------------------------
// テストメールを送信
//----------------------------
$FROM = $admin_email;
$TO = "$user$official_domain";
$SUBJECT= "TEST for $TO";
$HEAD = "From: $FROM";
$body = "This is TEST. Please ignore.";
mb_send_mail($TO, $SUBJECT, $body, $HEAD);
//----------------------------
// テストメールの通過を確認
//----------------------------
$output = cmd_exec("ssh $mta grep $gmail /var/log/maillog");
if (!preg_match('/GOOGLE.COM/', $output)) {
die("Can't confirm mail transfer\n");
}
//----------------------------------------
// Gmail 切り替え済みの案内メールを送る
//----------------------------------------
$SUBJECT="Gmailへの切替が完了しました";
$body = "$user 様\n\n" . file_get_contents($mailbody);
mb_send_mail($TO, $SUBJECT, $body, $HEAD);
sleep(3); // wait for mail transfer
//-------------------------------------
// メールアドレスを Gmail のみにする
// また、メール容量制限値を大きくしておく
//-------------------------------------
$result = $entry->replace(array(
'mail' => array($gmail),
'mailquota' => 999999));
if (Net_LDAP2::isError($result)) {
die(sprintf("LDAP modify FAILED: %s\n", $search->getMessage()));
}
$entry->update();
//---------------------------------------
// MailBox サーバから Maildir をコピー
//---------------------------------------
cmd_exec("sudo rm -rf /home/$user"); // just in case
cmd_exec("sudo rsync -az -e ssh --exclude='dovecot*' --bwlimit=102400 $imap_server:/home/$user /home");
//-------------------------------------------------------------------
// IMAP サーバにログインしてメール一覧を取得(インデックス再作成)
//-------------------------------------------------------------------
$imap->login($user, $pass);
if (PEAR::isError($imap)) {
die(sprintf("IMAP Login FAILED: %s\n", $imap->getMessage()));
}
printf("user=%s: IMAP login OK\n", $user);
$msgs = $imap->getMessagesList();
if (PEAR::isError($msgs)) {
die(sprintf("IMAP getMessagesList FAILED: %s\n", $msgs->getMessage()));
}
printf("user=%s: got %d messages\n", $user, count($msgs));
} // while()
情報センター Gmail 移行担当です。 Gmail早期移行のお申し込みありがとうございました。 Gmailが有効になりましたのでご利用ください。 Gmailへの入口は https://mail.google.com/a/example.com/ です。 Campusインデックスにもリンクを置いてあります。 これ以降、旧学内メール(ThunderBird/Active!mail)には新着メールが 届かなくなりますのでご注意ください。 また、これより過去メールの移行(コピー)を開始します。 過去メールの移行には、数時間~最大3日程度かかる予定です。 過去メールの移行中もGmailをご利用いただけます。 過去メールは Migrated というラベルがついた形で、徐々に皆さんのメール ボックスに取り込まれると思います。また、過去メールへの返信の形で 届いた新着メールにも Migrated ラベルがつくことがあるようです。 情報センターでは過去メールの移行完了を個別には監視いたしませんので、 移行完了のメールは差し上げません。 なお、学内メールの転送設定は自動移行されないのでご注意ください。 必要であれば、Gmail 側で再度メールの転送設定を行ってください。 Gmail について、簡単なマニュアルを http://pukiwiki.example.com/index.php?Gmail%2F%A5%DE%A5%CB%A5%E5%A5%A2%A5%EB に置いておりますのでご一読ください。 以上です。もし何か不都合などありましたらお知らせください。