Spis treści
Wstęp
Czasem istnieje potrzeba dowiedzenia się, czy nasza wiadomość e-mail została odczytana przed odbiorcę bez klikania potwierdzeń z jego strony. Istnieje na to dość stara, sprawdzona metoda dodawania śledzącego obrazka do wiadomości, postaram się ją przybliżyć osobom nie znającym tematu, dodatkowo przedstawię pomysł na prosty panel webowy, w którym można obserwować czy poszczególne wiadomości zostały odczytane oraz generować “kolejne” obrazki.
Działanie techniki
Samo działanie tej techniki jest proste: przy wysyłaniu wiadomości e-mail, dodajemy do niej w kodzie HTML obrazek, bez znaczenia jaki, dla przykładu czarny obrazek 1 na 1 piksel. Obrazek jest umieszczony na naszym serwerze, a więc żeby go pobrać klient pocztowy odbiorcy będzie musiał wykonać do nas zapytanie celem pobrania go. W momencie gdy przychodzi takie zapytanie wiemy już, że wiadomość została otworzona/odczytana przez odbiorcę. Schematycznie przedstawia się to tak:

Oczywiście obrazek nie musi być na tym samym serwerze co poczta, jest tu dowolność, rzecz w tym, że nadawca musi mieć dostęp do danych serwera, na którym obrazek jest przechowywany, aby dowiedzieć się, że został on pobrany.
Panel WWW – zarys + konfiguracja bazy danych
Przejdźmy do panelu WWW, który zautomatyzuje nieco cały proces. Samo założenie panelu jest następujące:
- Generujemy losowy, unikalny kod(identyfikator) dla każdej wysyłanej wiadomości
- Do wiadomości dodajemy tag <img> z linkiem do skryptu PHP wraz z naszym identyfikatorem
- Za pomocą PHP pobieramy identyfikator, na podstawie jego oznaczamy konkretną wiadomość jako odczytana oraz za pomocą funkcji generujemy obrazek 1×1
Na początek skonfigurujemy małą tabelę w bazie danych(w moim przypadku MySQL) na generowane klucze oraz pozostałe informacje:
CREATE DATABASE mail_tracking;
CREATE TABLE `emails` (
`key` CHAR(10) NOT NULL,
`email` CHAR(100) NOT NULL,
`opened` INT(1) NOT NULL,
`active` INT(1) NOT NULL
);
Od początku: tworzymy nową bazę danych o nazwie mail_tracking, w niej tabelę emails złożoną z 4 kolumn:
key – identyfikator dla każdej wiadomości
email – odbiorca wiadomości(dla naszej informacji)
opened – informacja, czy wiadomość została odczytana
active – informacja, czy śledzenie jest aktywne(o tym za chwilę)
Panel WWW – kod i działanie
Jeśli chodzi o sam panel webowy, jego kod przedstawia się następująco(dodałem komentarze do wszystkich ważnych funkcji, w razie wątpliwości w działaniu pozostaję do dyspozycji w komentarzach):
<?php
$db = new PDO("mysql:host=localhost;dbname=mail_tracking", "LOGIN", "HASŁO");
// połączenie z bazą danych za pomocą PDO
if($_POST['sub'] && $_POST['email']) { // sprawdzenie, czy został wysłany formularz, dodanie nowego klucza
$key = substr(md5(microtime()),rand(0,21),10); // generowanie nowego, losowego klucza(10 znaków litery + cyfry)
$in = $db->prepare("INSERT INTO `emails` VALUES(:key, :email, '0', '0')"); //
$in->bindParam(":key", $key); //
$in->bindParam(":email", $_POST['email']); // dodanie nowego klucza do bazy danych
$in->execute(); //
}
if($_GET['activate']) { // sprawdzenie czy śledzenie dla konkretnego klucza zostało aktywowane
$in = $db->prepare("UPDATE `emails` SET `active`='1' WHERE `key`=:key");
$in->bindParam(":key", $_GET['activate']); // aktualizacja rekordu w bazie, uruchomienie śledzenia
$in->execute();
}
$keys = $db->query("SELECT * FROM `emails`"); // pobranie wszystkich rekordów z bazy
?>
<!-- podstawowe informacje HTML, dodany bootstrap dla schludniejszego wyglądu -->
<html>
<head>
<link rel="stylesheet" type="text/css" href="bootstrap/css/bootstrap.min.css">
<title>Mail Tracking</title>
</head>
<body>
<!-- utworzenie tabeli dla wszystkich rekordów -->
<table style="width: 40%" class="table table-striped">
<thead>
<tr>
<th scope="col">Key</th> <!-- unikalny identyfikator -->
<th scope="col">Email</th> <!-- e-mail odbiorcy -->
<th scope="col">Opened</th> <!-- informacja czy wiadomość została otwarta -->
<th scope="col">Activate</th> <!-- informacja czy śledzenie jest aktywne -->
<th scope="col">Copy img</th> <!-- wygenerowany tag <img> dla szybkiego skopiowania -->
</tr>
</thead>
<tbody>
<?php
foreach($keys as $key) { // funkcja iterująca po wszystkich rekordach w tabeli
$opened = $key['opened'] == 1 ? "Opened" : "Not opened"; // zmiana wartości(1 = "Opened", 0 = "Not opened")
$imgtag = htmlspecialchars('<img src="https://deicide.pl/track/track.php?key='.$key['key'].'" style="display: none">'); // generowanie szybkiego tagu <img> do skopiowania
$active = $key['active'] == 1 ? "Activated" : '<a href="index.php?activate='.$key['key'].'">Acivate</a>';
// zmiana wartości(1 = "Activated", 0 = link do aktywacji śledzenia)
echo '<tr>';
echo '<th scope="row">'.$key['key'].'</th>'; // unikalny identyfikator
echo '<td>'.$key['email'].'</td>'; // e-mail odbiorcy
echo '<td>'.$opened.'</td>'; // informacja czy wiadomość została otwarta
echo '<td>'.$active.'</td>'; // informacja czy śledzenie jest aktywne / link do aktywacji
echo '<td>'.$imgtag.'</td>'; // tag <img> do szybkiego skopiowania
echo '</tr>';
}
?>
</tbody>
</table>
<form method="POST"> <!-- formularz do dodawania kolejnych kluczy -->
<input type="text" name="email" placeholder="Email">
<input type="submit" name="sub" value="Dodaj klucz">
</form>
</body>
</html>
Panel przedstawia się następująco:

Obrazek w PHP + śledzenie
Generowanie za pomocą PHP obrazka oraz wstawianie informacji o pobraniu go do bazy danych można osiągnąć w następujący sposób:
<?php
$db = new PDO("mysql:host=localhost;dbname=mail_tracking", "LOGIN", "HASŁO");
// połączenie z bazą danych
if($_GET['key']) {
$in = $db->prepare("UPDATE `emails` SET `opened`='1' WHERE `key`=:key AND `active`='1'");
$in->bindParam(":key", $_GET['key']);
$in->execute();
// aktualizacja rekordu w bazie danych, ustawienie opened na 1(wiadomość została odczytana)
// tylko jeśli śledzenie jest aktywne
}
header("Content-Type: image/png"); // ustawienie nagłówka HTTP Content-Type na image/png
$im = @imagecreatetruecolor(1, 1); // utworzenie obrazka 1x1
imagepng($im); // wyświetlenie obrazka w przeglądarce
?>
Wyjaśnienie aktywacji, przykład działania
No dobrze, ale o co chodzi z tą aktywacją? Otóż gdyby śledzenie za pomocą kodu z góry było aktywne, to sami byśmy się na nie łapali. Nasz klient pocztowy, przy tworzeniu wiadomości prawdopodobnie dla podglądu pobierze obrazek z naszego serwera, więc automatycznie zostanie ona oznaczona jako przeczytana. Celem uniknięcia tego błędu warto aktywować śledzenie dopiero po wysłaniu wiadomości.
Teraz krótki przykład działania, na początek generuję sobie w panelu nowy kod dla mojego adresu w GMail:

Następnie tworzę nową wiadomość HTML na ten adres, wpisuję losową treść i na koniec w kodzie dodaję znacznik skopiowany z panelu:

Wysyłam wiadomość, aktywuję śledzenie w panelu, następnie przechodzę na GMaila i otwieram wiadomość:

Przechodzę z powrotem do panelu i widzę, że wiadomość została odczytana.

Jest to tylko przykład panelu, całość można oczywiście bardziej ozdobić, dodać opcję wysyłania wiadomości bezpośrednio z niego celem mocniejszej automatyzacji, dodać Javascript aby łatwiej kopiować tag <img>, natomiast to już pozostawiam finezji osób korzystających/testujących pomysł.
Słowo na koniec
Jak widać śledzenie wiadomości nie jest skomplikowane, warto jednak wiedzieć, że część klientów pocztowych nie pobiera obrazków z wiadomości automatycznie. Zamiast tego wyświetlają one stosowny komunikat, że można pobrać obrazki klikając przycisk. W tym przypadku dopóki odbiorca go nie wciśnie, nie mamy możliwości dowiedzieć się czy odczytał wiadomość(chyba, że nam zwyczajnie odpisze :)).
Dlatego na większosci maili domyślnie otwieranie obrazków z zewnętrznych jest wyłączone, w ten sposób blokuje się rozmaite spam-mailingi które na tej podstawie sprawdzają, czy dany adres jest aktywny.
Zgadza się, uwzględniłem to na koniec wpisu 🙂 jednak grupa “ofiar” jest potencjalnie duża ze względu na mnogość dostawców usługi + konfiguracje typu email na smartfonie, dla przykładu klient poczty na iPhone pobiera obrazki bez pytania.
A wszystko dlatego, że twórcy różnych programów/systemów pocztowych rozkosznie ignorują sobie wspólne standardy.
Jakby każdy klient pocztowy respektował nagłówek Disposition-Notification-To: to nie byłoby kłopotu z potwierdzeniem przeczytania. A chociażby np. interfejs webowy Gmaila tego nie obsługuje…