職場内のメール環境変更に対する圧力を軽減するために、全ユーザについて過去メールの移行を管理者側で行うことにしました。これはその時に使ったスクリプトです。ドメイン名等は変えてあります。
本スクリプトを流した後、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 に置いておりますのでご一読ください。 以上です。もし何か不都合などありましたらお知らせください。