Walidacja adresów email

W trzeciej części poradnika dla początkujących email marketerów zajmiemy się procesem walidacji adresów email. Walidacja pomoże wychwycić i odfiltrować adresy niepoprawne składniowo, nieaktualne (domena wygasła), oraz takie, w których konfiguracja domeny lub serwera poczty nie pozwoli na dostarczenie maila.
Celem walidacji jest ograniczenie liczby wysyłanych maili do tych, które mają szansę być odczytane.
W dzisiejszym odcinku przedstawimy aż 3 skrypty składające się na kompletne rozwiązanie:
- skrypt przeprowadzający właściwą walidację Zend Validatorem na partii adresów
- skrypt dzielący bazę adresów na adresy w zaufanych domenach (np. wp.pl, onet.pl) i pozostałe
- skrypt dzielący bazę adresów na części w celu zrównoleglenia i przyspieszenia całego procesu
Walidacja adresów
Zacznijmy od skryptu validate.php, przeprowadzającego właściwą walidację Zend Validatorem na przekazanej mu partii adresów.
Aby go uruchomić, najpierw musisz ściągnąć bezpłatny pakiet Zend Framework w wersji 1.12.x Full. Następnie rozpakuj ściągnięte archiwum, po czym wypakowany katalog library/Zend przenieś do katalogu /usr/share/php (lub innego znajdującego się na ścieżce include_path w konfiguracji PHP na Twoim systemie).
ini_set( "error_reporting", E_ALL );
ini_set( "display_errors", 1 );
require_once "Zend/Loader/Autoloader.php";
$autoloader = Zend_Loader_Autoloader::getInstance();
if ( empty($argv[1]) ) {
$script = $argv[0];
die("usage: $script [column_number/-] [deep]\n");
}
$file = $argv[1];
if ( !file_exists($file) )
die("invalid file name $file\n");
$date = date( "Y-m-d H:i:s" );
$lines = file( $file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES );
$validator = new Zend_Validate_EmailAddress();
$validator->setOptions(array(
"deep" => true,
"mx" => (@$argv[3] == "deep")
));
$column = is_numeric(@$argv[2]) ? $argv[2] : -1;
foreach ( $lines as $line ) {
if ( $column != -1 ) {
$fields = explode("\t", $line);
$email = $fields[$column];
} else
$email = $line;
if ( !$validator->isValid($email) )
foreach ($validator->getMessages() as $message)
echo "$date\t$email\t$message\n";
}
Zaufane domeny
Jeśli nie czytając reszty artykułu próbowałeś uruchomić powyższy skrypt, zauważyłeś pewnie, że działa i tak naprawdę mógłby być jedynym skryptem składającym się na całe rozwiązanie, ale... działa bardzo powoli. A jednocześnie wykorzystuje znikomą ilość zasobów. Można więc go uruchomić w np. 10, 100, czy 500 instancjach, aby przyspieszyć cały proces. Do tego służą 2 kolejne skrypty.
Skrypt split.php dzieli bazę adresów na adresy w zaufanych domenach, oraz całą resztę. Dla adresów w zaufanych domenach nie przeprowadzamy głębokiej walidacji domeny wierząc, że jest ona aktualna i ma prawidłową konfigurację DNS. Dla pozostałych adresów przeprowadzamy pełną weryfikację.
Poniższa wersja rozpoznaje tylko 12 najważniejszych domen. Nasza pełna wersja rozpoznaje 115 domen i można dopisywać kolejne. Jeśli chciałbyś uzyskać pełną wersję, napisz na adres pomoc@fajne.it lub zadzwoń na numer 603 252 633. Możesz również dopisywać kolejne domeny samodzielnie.
$trusted_domains = array(
"gmail.com",
"yahoo.com",
"hotmail.com",
"wp.pl",
"gazeta.pl",
"onet.pl",
"o2.pl",
"go2.pl",
"tlen.pl",
"interia.pl",
"poczta.fm",
"post.pl",
);
$lines = file($argv[1], FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES );
$generic = array();
$trusted = array();
foreach ($lines as $line)
{
list($username,$domain) = explode("@", $line);
if (empty($username) || empty($domain)) {
echo "invalid line $line\n";
continue;
}
if (in_array($domain, $trusted_domains, true))
$trusted[] = $line;
else
$generic[] = $line;
}
file_put_contents($argv[2], implode("\n", $trusted)."\n");
file_put_contents($argv[3], implode("\n", $generic)."\n");
Szybciej, szybciej...
Ostatni skrypt validator.sh służy do sterowania całym procesem walidacji, w tym dzieleniem wejściowego pliku na części i zrównoleglaniem pracy skryptu validate.php:
infile=$1
group=$2
lines=$3
php split.php $infile in-trusted-$2.txt in-generic-$2.txt
split --lines=$lines in-generic-$2.txt part.$2.
for P in `ls part.$2.*`; do
php validate.php $P - deep $group >tmp.$2.$P &
done
php validate.php in-trusted-$2.txt - "" $group >out-trusted-$2.txt &
while [ "`ps aux |grep validate.php |grep $group |grep -v grep`" != "" ]; do
sleep 10
done
cat tmp.$2.part.* >out-generic-$2.txt
rm tmp.$2.part.* part.$2.*
cat out-trusted-$2.txt out-generic-$2.txt \
|grep -v checkdnsrr |grep -v ^$ >zend-errors-$2.csv
Jak to działa
Mamy już komplet skryptów, spróbujmy więc całość uruchomić:
sh validator.sh baza1.txt baza1 20000
Poniższe polecenie zakłada, że wejściowa baza adresów email do walidacji znajduje się w pliku baza1.txt i ma być walidowana w paczkach po 20 tysięcy adresów. Skrypt validator.sh utworzy tyle instancji skryptu validate.php, aby każda instancja przetwarzała po jednej paczce, oraz jedną dodatkową instancję dla adresów w zaufanych domenach.
Parametr "baza1" jest parametrem pomocniczym, służącym jako element nazwy plików tymczasowych i wyjściowych - dzięki niemu możliwe jest jednoczesne walidowanie kilku osobnych baz:
sh validator.sh baza1.txt baza1 20000 &
sh validator.sh baza2.txt baza2 80000 &
Efektem działania skryptu validator.sh będzie plik CSV o nazwie np. zend-errors-baza1.csv, zawierający listę komunikatów błędów znalezionych przez Zend Validator. Błędy te można próbować ręcznie naprawiać w pliku wejściowym (np. baza1.txt), lub po prostu zignorować (i tym samym zmniejszyć listę odbiorców swoich mailingów).
Pliki CSV generowane przez skrypt będzie można wraz z plikami CSV generowanymi przez skrypt do odbierania zwrotek potraktować jako dane wejściowe do klasyfikatora zwrotek i błędów walidacji, który opiszemy w jednym z kolejnych artykułów.
Całość jest przetestowana na Debianie Wheezy z PHP w domyślnej wersji 5.4.39, powinna jednak działać bez problemów w dowolnej wersji systemu Linux z zainstalowanym PHP.
Tomasz Klim
Administrator serwerów i baz danych, specjalista w zakresie bezpieczeństwa, architekt IT, przedsiębiorca. Ponad 20 lat w branży IT.
Pracował dla największych i najbardziej wymagających firm, jak Grupa Allegro czy Wikia.
Obecnie zajmuje się bezpieczeństwem projektów blockchainowych w Espeo Software.
Chętnie podejmuje się ciekawych zleceń.