Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Email Open Length Tracking with PHP

Tags:

php

I have been tracking emails for years using a "beacon" image and for those clients that allow the images to download it has worked great to track how many people have opened the email.

I came across the service "DidTheyReadIt" which shows how long the client actually read the email, I tested it with their free service and it is actually pretty close to the times I opened the email.

I am very curious in how they achieve the ability to track this, I am certain that whatever solution is chosen it will put a lot of load on the server / database and that many of the community will reply with "Stop, No and Dont" but I do want to investigate this and try it out, even if its just enough for me to run a test on the server and say "hell no".

I did some googling and found this article which has a basic solution http://www.re-cycledair.com/tracking-email-open-time-with-php

I made a test using sleep() within the beacon image page:

<?php 

set_time_limit(300); //1000 seconds
ignore_user_abort(false);  

$hostname_api = "*";
$database_api = "*";
$username_api = "*";
$password_api = "*";

$api = mysql_pconnect($hostname_api, $username_api, $password_api) or     trigger_error(mysql_error(),E_USER_ERROR);
mysql_select_db($database_api, $api);

$fileName = "logo.png";

$InsertSQL = "INSERT INTO tracker (FileName,Time_Start,Time_End) VALUES   ('$fileName',Now(),Now()+1)";
mysql_select_db($database_api, $api);
$Result1 = mysql_query($InsertSQL, $api) or die(mysql_error());
$TRID = mysql_insert_id();

//Open the file, and send to user.

$fp = fopen($fileName, "r");
header("Content-type: image/png");
header('Content-Length: ' . filesize($fileName));
readfile($fileName);

set_time_limit(60);
$start = time();

for ($i = 0; $i < 59; ++$i) {

// Update Read Time

$UpdateSQL = "UPDATE tracker SET Time_End = Now()  WHERE TRID = '$TRID'";
mysql_select_db($database_api, $api);
$Result1 = mysql_query($UpdateSQL, $api) or die(mysql_error());

time_sleep_until($start + $i + 1);
}

?>

The problem with the code above (other than updating the database every second) is that once the script runs it continues to run even if the user disconnects (or moves to another email in this case).

I added "ignore_user_abort(false);", however as there is no connection to the mail client and the headers are already written I dont think the "ignore_user_abort(false);" can fire.

I looked at the post Track mass email campaigns and one up from the bottom "Haragashi" says:

"You can simply build a tracking handler which returns the tracking image byte by byte. After every byte flush the response and sleep for a period of time.

If you encounter a stream closed exception the client has closed the e-mail (deleted or changed to another e-mail who knows).

At the time of the exception you know how long the client 'read' the e-mail."

Does anyone know how I could "simply build a tracking handler" like this or know of a solution I can implement into my code that will force the code to stop running when the user disconnects?

like image 504
jdublu Avatar asked Jun 29 '12 14:06

jdublu


People also ask

Can you track how long an email is open?

Email tracking notifies you when any email you sent has been opened or clicked. Email tracking software places an invisible image pixel in your emails that can detect the exact time and date an email has been opened by a recipient.

How do you track email open rates?

To determine the open rate for an email campaign, the number of unique opens is divided by the number of emails sent, minus those that bounced. In your account, the open rate percentage for sent campaigns can be seen on the Overview tab, or the Campaigns tab.


1 Answers

I think the problem is that you aren't doing a header redirect every so often. The reason that it is necessary is because once a script starts executing in PHP+Apache, it basically disregards the client until finished. If you force a redirect every X seconds, it makes the server re-evaluate if the client is still connected. If the client isn't connected, it can't force the redirect, and therefore stops tracking the time.

When I played around with this stuff, my code looked like:

header("Content-type: image/gif");
while(!feof($fp)) {
    sleep(2);
    if(isset($_GET['clientID'])) {
        $redirect = $_SERVER['REQUEST_URI'];
    } else {
        $redirect = $_SERVER['REQUEST_URI'] . "&clientID=" . $clientID;
    }
    header("Location: $redirect");
    exit;
}

If the client id was set, then above this block of code I would log this attempt at reading the beacon in the database. It was easy to simply increment the time on email column by 2 seconds every time the server forced a redirect.

like image 180
Jack Slingerland Avatar answered Oct 06 '22 19:10

Jack Slingerland