Zbliżam się właśnie do ukończenia aplikacji do wysyłania newsletterów. Zdawałoby się prosta sprawa ale specyfikacja zawierała kilka niespodzianek.
Zacznę może od założeń jakie wyżej wspomniana aplikacja spełnia.
Założenia
—
Subskrybentami newslettera są użytkownicy dwóch niezależnych portali, a dokładnie strony branżowej pewnej firmy oraz platformy stanowiącej pomost pomiędzy działem marketingu owej firmy oraz dziennikarzami. Oba z portali stoją na dwóch niezależnych serwerach.
Źródło „pochodzenia” dzieli w naturalny sposób subskrybentów na dwie kategorie. Ponadto system umożliwia ręczne grupowanie użytkowników według najróżniejszych parametrów. Każdy z subskrybentów może należeć do więcej niż jednej grupy.
Newsletter może być rozsyłany do jednej lub więcej grup subskrybentów przy czym zadbano o to aby żaden z użytkowników nie dostał danego biuletynu dwa razy.
Grupy subskrybentów posiadają priorytety decydujące o tym, którzy z subskrybentów otrzymają wiadomość jako pierwsi. Ponieważ pojedynczy newsletter może zostać zaadresowany do ponad 20 tys. adresatów, jego wysyłka może potrwać nawet kilka godzin. Jeśli w trakcie wysyłania jednego z biuletynów zostanie zredagowany i wysłany drugi newsletter to subskrybenci drugiego z priorytetem wyższym od adresatów pierwszego newslettera otrzymają wiadomość w pierwszej kolejności.
Człowiek istotą omylną jest, a co więcej swój błąd może dostrzec w chwili kiedy godzina „0” już minęła. Dlatego zaimplementowana została procedura wstrzymania wysyłki newslettera dająca możliwość dokonania drobnej korekty treści i kontynuowanie przerwanego procesu. Subskrybenci, którzy otrzymali wiadomość zawierającą błąd nie otrzymają poprawionej wiadomości.
Treść newslettera powstaje w kilku krokach – począwszy od zaplanowania, poprzez utworzenie, aż po akceptację. Następnie wraz z nastaniem określonej daty i godziny rozpoczyna się proces rozsyłania biuletynu do wybranych adresatów. Biuletyn wysyłany jest w formacie txt oraz html i może zawierać grafiki. Każdy z subskrybentów otrzymuje wiadomość spersonalizowaną przynajmniej w części zawierającej link z indywidualnym kodem autoryzującym umożliwiający wypisanie z newslettera. Po zakończeniu wysyłki treść wiadomości automatycznie kopiowana jest wraz z grafikami do aktualności w jednym z dwóch lub obu portalach.
Sprawy kluczowe
—
W trakcie implementacji największym problemem jest skala. Trudno przetestować wysyłanie newslettera do 20 tys. adresatów. Taką sytuację najprościej zasymulować uruchamiając na serwerze pocztowym usługę catch-all. Pozostaje wtedy jedynie wygenerować 20 tys. nieistniejących adresów mailowych, a wszystkie wiadomości trafią do utworzonej przez nas czarnej dziury. Nie jest to idealne rozwiązanie bo wszystko odbywa się w ramach jednej domeny.
Pojedynczą wiadomość trzeba wysłać do bardzo wielu subskrybentów. Intuicyjnie nasuwającym się rozwiązaniem byłoby wysłanie pojedynczego maila do pierwszego z adresatów, a reszta mogłaby teoretycznie otrzymać wiadomość na zasadzie ukrytej kopii. Nie jest to jednak dobry pomysł przynajmniej z kilku powodów. Po pierwsze (nie sprawdzałem tego, ale …) istniej zapewne ograniczenie liczby adresatów Bcc (blind carbon copy). Po drugie filtry antyspamowe nie chętnie przepuszczają tego typu wiadomości z uwagi na to, że tryb ten był kiedyś nagminnie stosowany do rozsyłania niechcianej poczty. Po trzecie nagłówki takich wiadomości zawierają informację o pierwotnym adresacie więc subskrybent jest w stanie łatwo się domyślić, iż dostał kopię, a to nie jest profesjonalne podejście. Po czwarte, ostatnie i rozstrzygające – poszczególne wiadomości pojedynczego newslettera są spersonalizowane (zwroty grzecznościowe, linki umożliwiające rezygnację z subskrypcji itp.). Trzeba wysyłać wiadomości pojedynczo, a jeśli wysyła się je w formacie html z dołączonymi grafikami do kilkudziesięciu adresatów to trzeba to robić partiami. Osobiście proponuję zatrudnić w tym celu crona, choć przychodzą mi do głowy też inne rozwiązania (i inne języki programowania jak Python na ten przykład).
Jak już jesteśmy przy kwestii wysyłania email-i za pośrednictwem PHP to polecam [Swift Mailer](http://swiftmailer.org/). Wersja 4 jest wygodniejsza w użyciu od poprzednich, a do tego napisana w PHP5 zatem obsługuje wyjątki co w przededniu 6 nie powinno już raczej dziwić 😉
Kolejnym wyzwaniem jest integracja dwóch niezależnych portali. Fizyczne rozdzielenie uniemożliwia współdzielenie zasobów tj. bazy danych czy katalogu z grafikami. W tej kwesti naturalnym rozwiązaniem wydaje się być SOAP. PHP5 ma już domyślnie dołączony dodatek napisany w C do obsługi SOAP-a, który bardzo ułatwia całą sprawę. Jedno czego nienawidzę w pracy z SOAP-em (i AJAX-em zresztą też choć w mniejszym stopniu) to debugowanie. Chwilę wahania miałem na etapie kopiowania grafik. Wystarczającym rozwiązaniem było by przesłanie SOAP-em linka do grafiki i zaciągnięcie jej np. CURL-em, tym bardziej że oficjalna specyfikacja traktująca o przesyłaniu danych binarnych SOAP-em nie wygląda zachęcająco. Chętnych zapraszam na stronę [SOAP Messages with Attachments](http://www.w3.org/TR/SOAP-attachments). Na szczęście da się to zrobić w dość prosty sposób przy pomocy Base64 i przesłać obrazki wraz z danymi tekstowymi. Prostą podpowiedź jak to zrobić znajdziemy na stronie [Being Binary in SOAP](http://blog.phpdeveloper.org/?p=88).