【PHP】メール送信処理にタイムアウト設定を追加して処理停止を回避する方法

【PHP】メール送信処理にタイムアウト設定を追加して処理停止を回避する方法 PHP

PHPでメール送信処理を行う際、外部のSMTPサーバーの応答が遅いと処理が停止し、ユーザーに不便を与えることがあります。この記事では、PHPでのメール送信処理にタイムアウト設定を加える方法を解説し、より安定した送信処理の実装を目指します。

メール送信時のタイムアウトが問題になる理由

mail()関数や外部ライブラリ(PHPMailerなど)を使ってメールを送信する際、送信先のSMTPサーバーが混雑していたり応答に時間がかかると、スクリプト全体が停止してしまうケースがあります。特にフォームからの自動返信など、ユーザーに即時反応を返したい場面では、こうした遅延がUXに悪影響を与えることがあります。

PHPのmail()関数におけるタイムアウト制御

PHPの標準関数mail()は内部でsendmailやSMTPなどを利用しますが、直接的にタイムアウトを設定する機能はありません。そのため、タイムアウトを制御するには設定ファイルやPHPの実行時間に工夫が必要です。

以下のコードのように、set_time_limit()で最大実行時間を制御することで、スクリプト全体の応答停止を防ぐことができます。

// 実行時間の上限を5秒に設定
set_time_limit(5);

$to = 'example@example.com';
$subject = 'テストメール';
$message = 'これはテスト送信です。';
$headers = 'From: webmaster@example.com';

if (mail($to, $subject, $message, $headers)) {
  echo 'メール送信に成功しました。';
} else {
  echo 'メール送信に失敗しました。';
}

ただし、これはメール送信処理に限定されたタイムアウトではなく、スクリプト全体の制御になるため細かな調整はできません。

PHPMailerでのタイムアウト設定

より詳細な制御を行いたい場合は、SMTPをサポートしたライブラリ「PHPMailer」の使用がおすすめです。PHPMailerでは、タイムアウトを明示的に設定することができます。

以下はその実装例です。

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

require 'vendor/autoload.php';

$mail = new PHPMailer(true);

try {
    // サーバー設定
    $mail->isSMTP();
    $mail->Host       = 'smtp.example.com';
    $mail->SMTPAuth   = true;
    $mail->Username   = 'your_user@example.com';
    $mail->Password   = 'your_password';
    $mail->SMTPSecure = 'tls';
    $mail->Port       = 587;

    // タイムアウト設定(秒)
    $mail->Timeout = 5; // ソケット接続のタイムアウト
    $mail->SMTPOptions = [
        'socket' => [
            'timeout' => 5
        ]
    ];

    // 送信元と宛先
    $mail->setFrom('from@example.com', 'Mailer');
    $mail->addAddress('to@example.com', '受信者名');

    // コンテンツ
    $mail->isHTML(true);
    $mail->Subject = 'タイムアウト設定付きのメール';
    $mail->Body    = 'このメールはPHPMailerで送信されています。';

    $mail->send();
    echo 'メール送信に成功しました。';
} catch (Exception $e) {
    echo 'メール送信に失敗しました: ', $mail->ErrorInfo;
}

$mail->TimeoutとSMTPOptionsでソケットレベルのタイムアウトも指定可能で、ネットワーク遅延などにも対処できます。

stream_context_createを使ったカスタム設定

SMTP通信のカスタム設定が必要な場合は、stream_context_create()を用いた方法もあります。これは fsockopen()や fopen() などの低レベル関数と組み合わせて使用しますが、PHPMailerのようなライブラリが内部で使用しているケースにも適用できます。

$context = stream_context_create([
    'socket' => [
        'timeout' => 5, // タイムアウト秒数
    ],
]);

// このコンテキストをfsockopenなどに渡して使用

タイムアウト処理とログ記録を組み合わせる

ネットワーク状況によっては断続的に失敗するケースもあるため、送信失敗時のログ記録や再送処理と組み合わせるとさらに堅牢なシステムになります。

if (!$mail->send()) {
    error_log('メール送信失敗: ' . $mail->ErrorInfo);
    // 必要に応じて再送処理や管理者通知などを実装
}

まとめ

PHPでメール送信処理を実装する際、ネットワークや外部SMTPサーバーの影響を受けやすく、遅延や処理停止のリスクがあります。set_time_limit()やPHPMailerのTimeout設定、stream_context_create()などを活用することで、より安定したメール送信が可能になります。

メール送信はフォームのUXやバッチ処理の信頼性に直結する重要な要素です。タイムアウト制御を正しく実装して、システムの安定性を向上させましょう。