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…