3

Wykrywanie odczytania wiadomości e-mail + panel WWW

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'] &amp;&amp; $_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 :)).

Avatar

glasn0st

3 Comments

  1. 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.

  2. 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…

Dodaj komentarz