在 HTML 郵件內嵌一張 1x1 像素透明圖片 (<img src="track.php?msg_id=123">),收信者開信載入圖片時,伺服器端 PHP 腳本記錄存取資訊並回傳圖片,即可達到開信追蹤。
<?php
// track.php
// 關閉錯誤輸出避免破壞圖片
error_reporting(0);
// 設定回傳為 JPEG
header('Content-Type: image/jpeg');
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Pragma: no-cache');
header('Expires: Thu, 01 Jan 1970 00:00:00 GMT');
// 取得客戶端 IP (考慮 Proxy)
function getClientIp(): string
{
$headers = ['HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR'];
foreach ($headers as $h) {
if (!empty($_SERVER[$h])) {
$ips = explode(',', $_SERVER[$h]);
return trim($ips[0]);
}
}
return 'unknown';
}
$ip = getClientIp();
$time = time();
$date = date('Y-m-d H:i:s', $time);
$ua = $_SERVER['HTTP_USER_AGENT'] ?? 'unknown';
$msgId = $_GET['msg_id'] ?? 'unknown';
// 記錄到檔案 (生產環境建議寫入資料庫)
$logLine = sprintf("%s\t%s\t%s\t%s\t%s\n", $date, $ip, $msgId, $ua, $_SERVER['HTTP_REFERER'] ?? '');
$logFile = __DIR__ . '/logs/email_track.log';
// 確保目錄存在
if (!is_dir(dirname($logFile))) mkdir(dirname($logFile), 0755, true);
// 檔案鎖定寫入 (避免併發衝突)
$fp = fopen($logFile, 'a');
if ($fp) {
flock($fp, LOCK_EX);
fwrite($fp, $logLine);
flock($fp, LOCK_UN);
fclose($fp);
}
// 產生 1x1 透明 JPEG
$img = imagecreate(1, 1);
$transparent = imagecolorallocatealpha($img, 255, 255, 255, 127);
imagefill($img, 0, 0, $transparent);
imagejpeg($img);
imagedestroy($img);
?>
<html>
<body>
<p>親愛的用戶,這是一封測試郵件。</p>
<!-- 追蹤像素,msg_id 對應郵件編號 -->
<img src="https://yourdomain.com/track.php?msg_id=20240115001" width="1" height="1" alt="" style="display:block;border:0;" />
</body>
</html>
<?php
// 使用 PDO
$pdo = new PDO('mysql:host=localhost;dbname=mailtrack;charset=utf8mb4', 'user', 'pass');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare(
"INSERT INTO email_opens (msg_id, ip, user_agent, opened_at, referer) VALUES (?, ?, ?, NOW(), ?)"
);
$stmt->execute([
$_GET['msg_id'] ?? null,
$ip,
$ua,
$_SERVER['HTTP_REFERER'] ?? null
]);
?>
-- 開信率 SELECT m.subject, m.sent_count, COUNT(DISTINCT o.id) AS open_count, ROUND(COUNT(DISTINCT o.id) / m.sent_count * 100, 2) AS open_rate FROM mail_campaigns m LEFT JOIN email_opens o ON o.msg_id = m.msg_id GROUP BY m.id; -- 重複開信次數分布 SELECT msg_id, COUNT(*) AS opens, COUNT(DISTINCT ip) AS unique_ips FROM email_opens GROUP BY msg_id; -- 熱門開信時段 (小時) SELECT HOUR(opened_at) AS hour, COUNT(*) AS cnt FROM email_opens GROUP BY hour ORDER BY hour;限制與道德考量
List-Unsubscribe 標頭或退訂連結讓用戶選擇退出追蹤msg_id 加入 HMAC 簽名防止竄改track.php?token=uuid,精準對應收件人正確實作追蹤像素,能為行銷活動提供寶貴的開信率數據,但務必遵守法規與用戶隱私權。