PHP: Run script to load image embedded in e-mail

This tip is useful for anyone who wants to know if the email you sent has been read. In this case, Insert an image in the body of the e-mail message, When is opened, will trigger a script on remote server.

Presentation

This technique is widely used in e-mail marketing, so that the sender sends hundreds or thousands of emails to your direct mail recipients in order to reach a target audience, and you know the feedback (return) the campaign, IE, If the recipient has read or not the propaganda embedded in the email.

How it works?
The reasoning is simple, you just put in the body of the email (content) a HTML image Tag, with the SRC attribute pointing, not directly to an image as is normally done, but for a custom script hosted on a remote server, where can you perform some routine and, then Yes, render an image (or not). Complicated? That nothing, see example:

1
2
3
<?PHP
  <img src="http://seuservidor.com/script.php?email=pessoa@gmail.com&recipient = Taylor + Lee" />
?>

For serving?
Note that when the user opens the e-mail, will automatically be charged the alleged image, which is actually a script. This is useful to make email statistics that have been viewed, including determining who opened (recipient) and when (date/time). Of course, that's no “divination”, We know who opened the e-mail, because we hold that data in the URL of the image when you upload it.

Inconvenience
For this to work, the recipient necessarily needs to be configured so that your email be read in HTML format, Although this is already a standard accepted by the majority of users. In the worst case, the email provider will display a message saying that blocked the images, but asking if the user wants to display, What is also commonly accepted, Since few people see malice in this practice. In the case of Google, a message appears in the form of a link, Like this:

1
2
3
...
  Images not displayed - Display images below - Always display images of suport@email.Microsoft.with
...

I will comment on two ways to do this; both works also, the second is more discreet not to display data in the URL, Although requires more storage resource. Come on.!

Solution 1

In practice
You need only two PHP codes:
(1) a to send the email in HTML format with embedded IMG tag
(2) and another to capture the information at the time the email is opened

STEP 1 – Send email

sendmail.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?PHP
  // *** Your email (who sends email)
  $remetente_nome     = ' Anonymous ';
  $remetente_email    = ' anonimo@email.com ';
 
  // *** Your target (email to who sends) 
  $destinatario_nome  = ' Mario Bross ';
  $destinatario_email = ' mariobross@email.com ';
 
  // *** Subject and message body
  $subject      = ' Testing the script execution when loading image. ';
  $message     = '
    <html lang="pt-br">
      <head>
        <meta charset="iso-8859-1" />    
        <title>'.$subject.'</title>
      </head>
      <body>
        <img src="http://seuservidor.com/script.php?email = '.UrlEncode($destinatario_email).'&recipient = '.UrlEncode($destinatario_nome).'&subject = '.UrlEncode($subject).'" />
      </body>
    </HTML>';
 
  // Header stating that the content is of type HTML (to be able to read the IMG tag and run the script)
  $header       = "MIME-Version: 1.0\n"; 
  $header      .= "Content-type: text/html; charset = iso-8859-1\n"; 
  $header      .= "From: ".(empty($remetente_nome) ? $remetente_email : '"'.$remetente_nome.'" <'.$remetente_email.'>')."\n";
 
  // Sends the email
  $email = empty($destinatario_nome) ? $destinatario_email : '"'.$destinatario_nome.'" <'.$destinatario_email.'>';
  mail($email, $subject, $message, $header);
?>

STEP 2 – Capture information

Well, did you notice when reading the IMG TAG will be made a call to the file “script.php”, right? So now we have to create it to get the information and store it, preferably in a database.

Creating TABLE
Since we need to persist the data of the recipient who opened the e-mail, We can create a table like this one below. See the field ' datahora_visualizado ', that refers to last date and time that the user viewed the email and the field ' counter ', that will register the amount of times that the e-mail was seen.

maladireta.sql
1
2
3
4
5
6
7
8
9
CREATE TABLE ' maladireta ' (
  ' id ' INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
  ' email ' VARCHAR( 100 ),
  ' recipient ' VARCHAR( 100 ),
  ' subject ' VARCHAR( 200 ),
  ' datahora_envio ' DATETIME NOT NULL,
  ' datahora_visualizado ' DATETIME,
  ' counter ' INT DEFAULT 0
) ENGINE = MYISAM ;

Script to capture information and display an image
Finishing, Let's get data as recipient's email, recipient's name, subject of the message and the date/time who opened the e-mail, storing everything in the database that we created, for if in the future we have to make a statistic. At the end of the script, Let's actually create and display an image, just to not be a IMG TAG with existential crisis :), But if you do not want to display nothing, create at least one blank image (1×1 pixel) not to get tagged broken.

script.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?PHP
  // Initializes and treats the input parameters
  $destinatario_email = trim(strip_tags(addslashes($_ REQUEST[' email '])));
  $destinatario_nome  = trim(strip_tags(addslashes($_ REQUEST[' recipient '])));
  $subject            = trim(strip_tags(addslashes($_ REQUEST[' subject '])));       
 
  // Connects to the database (ADJUST YOUR CONNECTION)
  $link = mysql_connect(' mysql.seuservidor.com ', 'root', ' *** *** mypassword ') or Die(' Failed to connect to the database. '); 
  mysql_select_db(' seubancodedados ') or Die(' Failed to select database ');
 
  // Mount the SQL and inserts to the database, If email does not exist, or updates counter if there
  $SQL = 'SELECT email FROM maladireta WHERE email="'.$destinatario_email.'"';
  $RES = mysql_query($SQL);
  if (mysql_num_rows($RES) > 0) {
    $SQL = 'UPDATE maladireta SET datahora_visualizado="'.date(' Y-m-d H:(I):s ').'", contador=contador+1 WHERE email="'.$destinatario_email.'"';    
  }
  else {
    $SQL = ' INSERT INTO maladireta VALUES (null, "'.$destinatario_email.'", "'.$destinatario_nome.'", "'.$subject.'", "'.date(' Y-m-d H:(I):s ').'", null, 0)';
  }
  mysql_query($SQL);
 
  // Creates and displays the embedded image to email
  header("Content-type: image/png");
  $IMG = imagecreatefrompng("imagem.png");
  imagepng($IMG);
  imagedestroy($IMG);
?>

Note: Don't forget to put together the script an image, where, I called “imagem.png”. This image will appear in the body of the email of the recipient, and that's where the marketing people put advertising, but it can be a logo or whatever you desire. The Script has been tested and works!

Solution 2

Another possibility
As suggested by Mr Leandro, a more discreet option and “safe” It would be, instead of stamping in the URL of the image a lot of data such as e-mail, subject, etc, create a HASH at the moment of sending the email linking to this data, and send in the URL only the HASH. When the recipient opens the e-mail and load the image, will travel only the HASH that then will be captured by our script and bound to the data that we want to know.

Creating the hash table and data link
We will create the table that will be populated every time we send an email. Note the field ' hash ', that will serve as a link in the e-mail that was sent and the recipient data that were stored in the.

maladireta.sql
1
2
3
4
5
6
7
8
9
10
CREATE TABLE ' maladireta ' (
  ' id ' INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
  `hash' VARCHAR( 50 ) NOT NULL,
  ' email ' VARCHAR( 100 ),
  ' recipient ' VARCHAR( 100 ),
  ' subject ' VARCHAR( 200 ),
  ' datahora_envio ' DATETIME NOT NULL,
  ' datahora_visualizado ' DATETIME,
  ' counter ' INT DEFAULT 0
) ENGINE = MYISAM

Sending the email

sendmail.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?PHP
  // *** Your email (who sends email)
  $remetente_nome     = ' Anonymous ';
  $remetente_email    = ' anonimo@email.com ';
 
  // *** Your target (email to who sends) 
  $destinatario_nome  = ' Mario Bross ';
  $destinatario_email = ' mariobross@email.com ';
 
  // *** Other data to persist and hashing (handle)
  $hash               = MD5(RAND());
  $subject            = ' Testing the script execution when loading image. ';
  $datahora_envio     = date(' Y-m-d H:(I):s ');
 
  // Connects to the database
  $link = mysql_connect(' mysql.seuservidor.com ', 'root', ' *** *** mypassword ') or Die(' Failed to connect to the database. '); 
  mysql_select_db(' seubancodedados ') or Die(' Failed to select database ');  
 
  // Mount the SQL and inserts to the database
  $SQL = ' INSERT INTO maladireta VALUES (null, "'.$hash.'", "'.$destinatario_email.'", "'.$destinatario_nome.'", "'.$subject.'", "'.$datahora_envio.'", null, 0)';
  mysql_query($SQL);
 
  // *** Message to be sent
  $message     = '
    <html lang="pt-br">
      <head>
        <meta charset="iso-8859-1" />    
        <title>'.$subject.'</title>
      </head>
      <body>
        <img src="http://seuservidor.com/script.php?hash = '.$hash.'" />
      </body>
    </HTML>';
 
  // Header stating that the content is of type HTML (to be able to read the IMG tag and run the script)
  $header       = "MIME-Version: 1.0\n"; 
  $header      .= "Content-type: text/html; charset = iso-8859-1\n"; 
  $header      .= "From: ".(empty($remetente_nome) ? $remetente_email : '"'.$remetente_nome.'" <'.$remetente_email.'>')."\n";
 
  // Sends the email
  $email = empty($destinatario_nome) ? $destinatario_email : '"'.$destinatario_nome.'" <'.$destinatario_email.'>';
  mail($email, $subject, $message, $header);
?>

Note that, in this case, the URL (SRC) the image is only with the HASH.

Accounting for email displayed

script.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?PHP
  // Capture the email HASH displayed
  $hash = trim(strip_tags(addslashes($_ REQUEST[' hash '])));
 
  // Connects to the database
  $link = mysql_connect(' mysql.seuservidor.com ', 'root', ' *** *** mypassword ') or Die(' Failed to connect to the database. '); 
  mysql_select_db(' seubancodedados ') or Die(' Failed to select database ');
 
  // Mount the SQL and display date email updates and counter in the database
  $SQL = 'SELECT hash FROM maladireta WHERE hash="'.$hash.'"';
  $RES = mysql_query($SQL);
  if (mysql_num_rows($RES) > 0) {
    $SQL = 'UPDATE maladireta SET datahora_visualizado="'.date(' Y-m-d H:(I):s ').'", contador=contador+1 WHERE hash="'.$hash.'"';
    mysql_query($SQL);
  }
 
  // Creates and displays the embedded image to email
  header("Content-type: image/png");
  $IMG = imagecreatefrompng("imagem.png");
  imagepng($IMG);
  imagedestroy($IMG);
?>

Oh, If you want to check the emails that were viewed from a date, could make a script with a SQL type that, where, Search all recent records of e-mail seen from 27 January 2013. The hint…

1
2
3
4
5
6
7
8
 
  SELECT * 
  From ' maladireta ' WHERE counter > 0 And 
      DATE(datahora_visualizado) >= DATE("2013-01-27")
;
Total hits: 34932

8 comments on “PHP: Run script to load image embedded in e-mail

  1. Leandro Chaves said:

    Taylor,
    It's not a good practice to put the user's email on the link of the image. The ideal is to insert the data in the Bank at the time of the shipment and put a hash or the id of the table on the link, to identify who opened the e-mail.

    • Hi Leandro, Thanks for the comment. That is debatable. Thinking on information you have reason, but in practice it would be okay preciousness, because the email link (image) that you consider important to protect is available only in the Inbox of the recipient itself. Is the same as hiding something from me that I know! In addition, you have to keep on your bench another table with thousands of records from your direct mail, even without knowing if the e-mails contained there are valid. Then if you wanted to “enchugar” your bank, could not, as for the sake of referential integrity between tables, would be required to maintain records, under penalty of never knowing who opened the e-mail. But since we're talking about safety, to avoid having the e-mail blocked by a Wireshark of life, What could be done is to use SSL (HTTPS) both in sending the email, as in the image link. But I like your proposal, I'll post a solution so, Thanks!

  2. OLA ,
    I'm trying to get the IP of the person who read the message , However if a hotmail account for example he grabs an IP with domain range in the U.S.. It does not help me much . How do I get the real IP of the machine it ?

  3. Régis said:

    Stranger sometimes works and sometimes does not work using Chrome, Opera and Fire Fox in gmail and hotmail – clear the cache and cookies, but the times doesn't make the recording in BD if the email was opened or not !!

  4. Diego said:

    Guys.. I have a script to register with name email…CPF…rg…wanted after user register everything and send to my database …Returns to his automatic e-mail.. type
    EXAMPLE:”information registered successfully..” wait our contact

    Would??

    • Oops, as said in the Post: “For this to work, the recipient necessarily needs to be configured so that your email be read in HTML format”. By default the HTML that is rendered, But even the Gmail change the rendering for TEXT, Hence won't work, because he will simply display the HTML TAGs as text rather than rendering them.

Leave a reply

The your email address will not be published. Required fields are marked with *