Przeglądarki blokują powtarzające się polecenia przekierowania, po pierwsze aby uchronić klienta przed "wędrowaniem" po wielu stronach i zbieraniem różnego rodzaju śmieci (cookiesów), a także przed wpadnięciem w nieskończoną pętlę. Zamiast funkcji header po stronie serwera może użyj meta tagu w kodzie odpowiedzi:
<meta http-equiv="refresh" content="1;url=http://adres_skryptu" />
Skrypt może wstawiać ten tag do nagłówka html'a tak długo, aż zostaną wysłane wszystkie maile. Można też użyć ajax, który będzie w pętli wywoływał skrypt tak długo, jak długo zwraca pewną ustaloną wartość: po wysłaniu wszystkich maili skrypt zwróci pusty tekst jako odpowiedź i pętla zostanie przerwana.
Zaletą ajaksowego rozwiązania jest brak
migotania strony w oknie przeglądarki i możliwość zrobienia ładnego, w pełni funkcjonalnego paska postępu (wykorzystaj jQuery).
Załączam gotowca (efekt prokrastynacji, czyli poniedziałkowej niechęci do zaplanowanej pracy

)
Aby sprawdzić działanie wystarczy:
1. umieścić na serwerze dwa pliki: sendmail.php i mailing.html (źródła poniżej),
2. do podkatalogu js wrzucić bibliotekę jQuery
http://docs.jquery.com/Downloading_jQuery3. utworzyć w bazie danych przykładową tabelę:
CREATE TABLE `tbl_mailing` (`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, `mail` VARCHAR(255), `status` ENUM ('waiting','sent'));
i wypełnić ją danymi, lub dodać pole `status` ENUM ('waiting','sent') do swojej tabeli.
Skrypt działający "w tle", realizujący wysyłanie maili partiami, zwracający do klianta informacje o procentowym postępie, lub zakończeniu wysyłki, nazwa skryptu
sendmail.php<?php
define(TABLE_MAILING
, '`tbl_mailing`'); define(HOW_MANY_EMAILS_AT_ONCE
,25
);
$db = new mysqli(HOST,USER,PASSWORD,DATABASE);
// pole `status` jest zdefiniowane jako: `status` ENUM ('waiting','sent')
// Ilość wszystkich maili:
$total = $db->query('SELECT COUNT(id) FROM '.TABLE_MAILING)->fetch_row();
// pobieramy maile oczekujące na wysłanie
$ans = $db->query('SELECT * FROM '.TABLE_MAILING.' WHERE `status`=\'waiting\' ORDER BY `id` ASC LIMIT 0,'.HOW_MANY_EMAILS_AT_ONCE);
while($row = $ans->fetch_row()) {
echo $row[0].':'.$row[1].'<br />';
/* -- TUTAJ REALIZUJEMY LOGIKĘ ZWIĄZANĄ Z WYSYŁANIEM MAILI -- */
// budujemy listę maili, których wysłanie zakończyło się sukcesem
}
$db->query('UPDATE '.TABLE_MAILING
.' SET `status`=\'sent\' WHERE `id` IN ('.implode(',',$confirm).')');
// Ilość pozostałych do wysłania
$waiting = $db->query('SELECT COUNT(id) FROM '.TABLE_MAILING.' WHERE `status`=\'waiting\'')->fetch_row();
// Zwracamy procentowy postęp wysyłania maili lub potwierdzenie zakończenia
if($waiting[0]) {
$sent = $total[0] - $waiting[0];
<input type="text" id="percent" value="'.(round(100
*$sent/$total[0], 2)).'" /> ';
} else
echo '<input type="text" id="finished" value="yes" />';
Frontend dla klienta: nazwa pliku np.
mailing.html (oczywiście może być wygenerowany przez php)
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pl"> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-language" content="pl" /> <script type="text/javascript" src="js/jquery.js" ></script> <script type="text/javascript"> function loader() {
$.ajax({
type: "GET",
url: "sendmail.php",
cache: "false",
data: "",
success: function(msg) {
$("#data").empty().append(msg);
if($("#finished").val()=="yes") {
// unikamy błędów zaokrągleń i błędu przy odświeżeniu strony:
$("#progressBar").css("width","800px");
alert("Gotowe !");
return;
}
$("#progressBar").css("width", (Math.round($("#percent").val()*8)) + "px" );
setTimeout("loader()",1); // unikamy wywołania rekurencyjnego!
},
handleError: function() { alert("hm..."); }
});
}
onload = function() {
loader();
}
body { text-align:center; }
div#body { width:900px;margin:0px auto 0px auto; border:1px solid #eee;padding:25px;}
div#container { margin:0px auto 0px auto;width:800px;border:1px solid #000; }
div#progressBar { height:20px;width:0px;background-color:#000066;margin:0px;padding:0px;font:8pt/12pt arial,tahoma,verdana,helvetica; }
<div id="data" style="display:none"></div>