Tracking email with PHP and image

49,709

Solution 1

Basically, in the HTML body of your email, there will be an <img> tag that would look like this :

<img src="http://www.yoursite.com/tracker.php?id=123456" alt="" />

When someone reads his mail, with images enabled, the email-client will send a request to tracker.php, to load the image, passing it id=123456 as a parameter.


This tracker.php script will be on your server, and, when called, it will :

  • Check the id parameter,
  • Use it to find to which email address it corresponds -- when generating the email for each one of your subscribers, you'll have generated an id different for each e-mail.
  • Do some stuff -- like log "email 123456 has been opened", and some additional informations
  • return the content of a small image ; like a 1x1 transparent gif.


The tracker.php script knows from which IP address it's been called -- like any other PHP script :

$ipAddress = $_SERVER['REMOTE_ADDR'];

And, starting from this IP address, you can use a geolocation service to find out from where in the world the email has been opened.
As a couple of examples, you could take a look at MaxMind, or IPInfoDB

As you know that id=123456 corresponds to one specific email address, this allows to find out where each one of your subscribers are.

Solution 2

1. Place the tracker image at the E-mail

<img src="http://www.yoursite.com/tracker.php?eid=123456&uid=123" alt="" width="1px" height="1px">

Its working is very simple, Once your mail is open, that tracker image sends the request to the server, from that request we can get information by creating the image URL with userID, and also consider as that mail is read by the user.

Note: Don't use display: none; property for hiding your images, it may filter by spam algorithm. And don't place any javascript codes, it also blocks the spam filter

2. On the tracker.php

<?php
header("Content-Type: image/jpeg"); // it will return image 
readfile("img.jpg");

dbfunction(); // place your db code
?>

3. The ip address is get by the following function.

function get_client_ip() {
    $ipaddress = '';
    if (isset($_SERVER['HTTP_CLIENT_IP']))
        $ipaddress = $_SERVER['HTTP_CLIENT_IP'];
    else if(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
        $ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
    else if(isset($_SERVER['HTTP_X_FORWARDED']))
        $ipaddress = $_SERVER['HTTP_X_FORWARDED'];
    else if(isset($_SERVER['HTTP_FORWARDED_FOR']))
        $ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
    else if(isset($_SERVER['HTTP_FORWARDED']))
        $ipaddress = $_SERVER['HTTP_FORWARDED'];
    else if(isset($_SERVER['REMOTE_ADDR']))
        $ipaddress = $_SERVER['REMOTE_ADDR'];
    else
        $ipaddress = 'UNKNOWN';
    return $ipaddress;
}
$PublicIP = get_client_ip();

4. Location:

The location is getting by any geolocation services, you can use open-source GeoLocation finder like nekudo,freegeoip.

for example

<?php
$json  = file_get_contents("http://ipinfo.io/$PublicIP/geo");
$json  =  json_decode($json ,true);
$country =  $json['country_name'];
$region= $json['region_name'];
$city = $json['city'];
?>

Solution 3

The other answers are great but, since humanity seems convinced that "any tracking is evil tracking" I like to take it a step further by being "invisible" to the user by retaining the .png/.jpg/.gif etc image file extension.

I'm not sure about compatibility with all types of web servers and hosts, but for me it was a quick change to the AddHandler directive I already had in .htaccess, such as:

AddHandler application/x-httpd-lsphp .png 

...to allow processing of PHP code within files with a .png extension.

You might already have an AddHandler line to allow PHP in .htm/.html files; if so, just add the appropriate image file extension to the end of the list.

This is, roughly, my "tracking image" code, file saved as trackimage.png or whatever :

<?php //silently log user and return image
  $ip=$_SERVER['REMOTE_ADDR'];
  $uri=tidy($_SERVER['SCRIPT_URI']);
  $querystring=tidy($_SERVER['QUERY_STRING']);
  $useragent=tidy($_SERVER['HTTP_USER_AGENT']);

  $json  = file_get_contents("https://ipinfo.io/".$ip."/geo");
  if(($json<>'')&&(strpos($json,"error")===false)){ extract(json_decode($json ,true)); }
  $country=tidy($country);
  $prov=tidy($region);
  $city=tidy($city);
  list($lat,$lon)=explode(',',$loc);
  $lat=tidy($lat);
  $lon=tidy($lon);

  $sql = "INSERT INTO img_track_table set ip='$ip', useragent=$useragent, uri=$uri, " 
    ."querystring=$querystring, country=$country, prov=$prov, city=$city, lat=$lat, lon=$lon;";

  require 'connect.php'; $conn=new mysqli($servername, $username, $password, $dbname);
  if ($conn->connect_error) { /* couldn't connect, but do nothing about it */ } 
  }else{  //run insert query
    if(!$conn->query($sql)) { /* query error, but do nothing about it */ }
    $conn->close();
  }

  //return image
  header("Content-Type: image/png"); 
  readfile("myActualImageFile.png");

  function tidy($str){ //remove quotes and backslashes from string
    if(is_null($str)||($str=="")){return "null";}
    $str=trim(str_replace('\\','',str_replace("'","",str_replace('"',"",$str))));
    if(is_numeric($str)){return $str;}
    return "'$str'"; 
  }

Note that if error text, or anything else, is returned by the code before the image, the image will be undisplayable. It might also be worth researching possible security concerns with this that might apply to you case. For example, this.

Solution 4

About the first part of the question, what I did was return the image from a PHP file. Aside from returning an image (it can be 1x1 pixel transparent png) is logging all the info into the database. This way, when the PHP file is called, you know that the image was loaded i.e. the email was read. The problem is that a lot of modern clients don't load images automatically. This is to not allow just the kind of thing you're trying to do, for privacy reasons.

About the second part, there are several geolocation web services, where you submit an IP and get the geolocation. You can do that in the PHP file that returns the 1x1 pixel image. Here is a good thread about this on this site: Geolocation web service recommendations

Share:
49,709
esafwan
Author by

esafwan

I Started with DOS, grew up with Windows and Matured with GNU/Linux. Was a Hardcore gamer, later interest shifted to programing and graphic designing. Is passionate when it comes to debating. Hates working under someone and has never so far. Currently busy building a career that is free from boss and hunger for money!

Updated on January 25, 2020

Comments

  • esafwan
    esafwan over 4 years

    I have seen the service like spypig.com placing a small image in the email and tracking when it is opened and from where. They track city, country, IP address etc. How is this done?

    1. How do we know when the mail is opened? And how is the image generated?
    2. How is the IP address detected and how is it possible to know location from it?
  • Gnanam
    Gnanam over 11 years
    May be I may not have understood completely. I just wanted to understand why we need to return the content of a small image. What would happen if we have like this <img src="http://www.yoursite.com/tracker.php?id=123456" alt="" style="display:none"/>? That is, set to display:none. Could you please throw some light on this?
  • aleation
    aleation over 11 years
    I guess you could skip returning an image, but it will be ugly showing the broken image icon. And I don't recomend you using display:none on a email, as the Spam filters are pretty strict nowadays and using that could make your email go straight away into the spam folder or maybe even reject it, because the filter will think you are hiding malicious text or code. Even using white text over white background could trigger this action
  • Mohammad Faisal
    Mohammad Faisal over 11 years
    how to return the image from tracker.php?
  • neridaj
    neridaj about 10 years
    Why not use another image in the email content, one that is actuallty meant to be rendered, i.e., logo, header image, etc?
  • TheBlackBenzKid
    TheBlackBenzKid about 10 years
    Can the PHP email actually get the email address of the recipient?
  • Admin
    Admin almost 10 years
    To hide the image, the easiest way seems to be: <img src="http://www.yoursite.com/tracker.php?id=123456" alt="" width="1" height="1" border="0">
  • Makio
    Makio about 9 years
    it will not work when user use an application to open email (iphone mail app for example )
  • Niladri Banerjee - Uttarpara
    Niladri Banerjee - Uttarpara almost 9 years
    Also, if someone reads the email offline, this method will not work. Am I correct?
  • andeersg
    andeersg almost 8 years
    Maybe I'm wrong, but the ipecho-part would have to be called on the server, so you would only get the IP-address of the server?
  • chirag satapara
    chirag satapara over 7 years
    $ipAddress = $_SERVER['REMOTE_ADDR']; not return the corrent ip address , it return a 66.249.84.194 ip address which is belong to the google , any one can help me to solve this.
  • Admin
    Admin about 7 years
    @Pascal MARTIN You are providing id for each mail, and each mail can be viewed by either sender or recipient. How to know which user has opened the email?
  • CGriffin
    CGriffin about 7 years
    I've found that this method doesn't seem to work in the Outlook email desktop client, is there any reason/workaround for this?
  • Nick Oetjen
    Nick Oetjen about 4 years
    Thanks, very useful. The AddHandler did not do the job for me, but AddType application/x-httpd-php .php .png