Mantisのメールキューをまとめ送りに改造

Mantisのメールアラートは非常に便利なのですが、結構届きすぎるんですよね。
チケットを登録して、担当をアサインして、よくみたら間違っていたので修正してとどんどん同じチケットのメールが届きます(笑)

まとめ送りとは?

MLとかのまとめ送りを最初イメージしたのですが、さすがにチケットをすべて1本にまとめて一時間に一本送るのは乱暴かなって思って、同一のチケットをまとめて送るようにしました。今回は30分ごとにcronで起動する想定ですが、毎分チェックして送信後30分は送らないなどの処理の方がいいかもしれません。

処理の概要

まとめ送りようの処理をコピーして、複数のメールをまとめて送っています。内容的には結構シンプルに対応が可能です。send_emails.phpをベースにしています。1.1.2ではこのファイルがあるのですが、1.2.0aだとこのファイルなくなっていますね。。。でもコピーしたら動きました!

処理

email_send_all_one関数が新規で作成したものです。送信先と題名でグルーピングして本文をくっつけて送信しています。くっつけた分のメールはemail_queue_delete関数を使って消してあげます。

<?php
#!/usr/local/bin/php -q
# Mantis - a php based bugtracking system

# Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
# Copyright (C) 2002 - 2007  Mantis Team   - mantisbt-dev@lists.sourceforge.net

# Mantis is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# Mantis is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Mantis.  If not, see <http://www.gnu.org/licenses/>.
	# See the README and LICENSE files for details

	# --------------------------------------------------------
	# $Id: send_emails.php,v 1.1.2.2 2007-10-26 13:36:15 giallu Exp $
	# --------------------------------------------------------

	global $g_bypass_headers;
	$g_bypass_headers = 1;

	require_once( dirname( dirname( __FILE__ ) ) . DIRECTORY_SEPARATOR . 'core.php' );

	$t_core_path = config_get( 'core_path' );

	require_once( $t_core_path . 'email_api.php' );

	# Make sure this script doesn't run via the webserver
	# @@@ This is a hack to detect php-cgi, there must be a better way.
	if ( isset( $_SERVER['SERVER_PORT'] ) ) {
		echo "send_emails.php is not allowed to run through the webserver.\n";
		exit( 1 );
	}

	echo "Sending emails...\n";
	email_send_all_one();
	echo "Done.\n";

	exit( 0 );

	function email_send_all_one() {
		$t_ids = email_queue_get_ids();

		$t_start = microtime_float();
		$t_email_list = array();
		foreach ( $t_ids as $t_id ) {

			$t_email_data = email_queue_get( $t_id );

			if( $t_email_data == null ){
				continue;
			}

			$email		= $t_email_data->email;
			$subject	= $t_email_data->subject;
			$email_id	= $t_email_data->email_id;

			$t_email_list[$subject][$email][] = $email_id;

		}

		foreach ( $t_email_list as $t_subject_list ) {

			foreach ( $t_subject_list as $t_email_list ) {

				if( count( $t_email_list ) == 1 ){
					// single send
					$t_email_data = email_queue_get( $t_email_list[0] );

					if ( !email_send( $t_email_data ) ) {
						echo "single send error ". $t_email_list[0] ."\n";

						if ( microtime_float() - $t_start > 5)
							break;
						else 
							continue;
					} else {
						echo "single send ". $t_email_list[0] ."\n";
					}

				} else {
					// multi send
					$t_email_body_list = array();
					foreach ( $t_email_list as $t_id ) {
						$t_email_body_list[] = email_queue_get( $t_id )->body;
					}
	
					$t_email_body = count($t_email_list) . "Mails Send.\n\n" . implode( "\n\n-------------------------------------------------\n\n", $t_email_body_list );

					$t_email_data = email_queue_get( $t_email_list[0] );
					$t_email_data->body = $t_email_body;

					if ( !email_send( $t_email_data ) ) {
						echo "multi send error ". implode( ", ", $t_email_list ) ."\n";
						if ( microtime_float() - $t_start > 5)
							break;
						else 
							continue;
					} else {
						echo "multi send ". implode( ", ", $t_email_list ) ."\n";

						while( array_shift($t_email_list) ){
							// mail delete(fast mail_id is excluded. )
							email_queue_delete( $t_email_list[0] );
						}
					}

				}
			}

		}

	}

事前設定

<?php
$g_email_send_using_cronjob = true;

上記の設定でまとめ送りをするようにしてから、コードをcoreの中にsend_emails_one.phpをコピーします。あとは通常の send_emails.php と同じように cron とかで定期的に呼び出してあげます。短くても10分から30分ぐらいの間隔にした方がいいと思います。

実験はWeb経由で実行していたのでコマンド以外の場合は exit( 1 ); で終了しているところをコメントアウトして、core の .htaccess を消して実験していました。

感想

いろいろ送り方は設定できると思いますが、今回はこんな感じにしてみました。本当は翻訳ファイルとかみて処理を作った方がきれいですがハードコーディングしちゃっています。(よく見たらメールの区切りとかも設定ファイルにあります。。。)

1.1.2と1.2.0a1で動作確認しています。