SmtpClient w Pythonie odnosi się do biblioteki smtplib, wykorzystywanej do wysyłki wiadomości ze skryptów.
Rola SmtpClient w Pythonie i biblioteka smtplib
Określenie „SmtpClient” nie jest nazwą wbudowanej klasy biblioteki standardowej Pythona. W praktyce odnosi się zwykle do klienta SMTP utworzonego przy użyciu modułu smtplib. Moduł ten pozwala programowi nawiązać połączenie z serwerem poczty wychodzącej, przeprowadzić rozmowę zgodną z protokołem SMTP oraz przekazać wiadomość do dalszej obsługi przez serwer. Sam Python nie dostarcza skrzynki pocztowej ani serwera wysyłającego; skrypt musi korzystać z danych dostępowych i adresu usługi SMTP udostępnionej przez dostawcę poczty.
Najczęściej używa się klasy smtplib.SMTP, gdy połączenie rozpoczyna się bezpośrednio jako sesja SMTP, oraz klasy smtplib.SMTP_SSL, gdy szyfrowanie TLS ma być aktywne od momentu utworzenia połączenia. Obie klasy reprezentują klienta komunikującego się z serwerem. Typowy przebieg obejmuje utworzenie obiektu, opcjonalne powitanie EHLO, negocjację szyfrowania, uwierzytelnienie metodą login() oraz wysłanie danych przez sendmail() albo send_message().
Nawiązanie sesji, TLS i uwierzytelnianie
Przy połączeniu realizowanym przez SMTP skrypt może użyć metody starttls(). Wtedy klient wysyła do serwera żądanie przejścia z nieszyfrowanej części sesji do połączenia chronionego przez TLS. Po pomyślnej negocjacji należy ponownie wywołać ehlo(), ponieważ serwer może przedstawić po szyfrowaniu inny zestaw obsługiwanych rozszerzeń. Do kontroli certyfikatu i parametrów TLS można przekazać obiekt ssl.SSLContext, zamiast pozostawiać konfigurację wyłącznie ustawieniom domyślnym środowiska.
SMTP_SSL przeznaczono do połączeń, w których TLS jest uruchamiany od razu podczas tworzenia kanału. Nie należy bezkrytycznie zamieniać tego trybu na starttls(), ponieważ są to dwa różne sposoby ustanawiania zabezpieczonej sesji i muszą odpowiadać konfiguracji konkretnego serwera. Numer portu również wynika z konfiguracji dostawcy. W dokumentacji usług pocztowych często spotyka się port 587 dla przesyłania wiadomości z użyciem uwierzytelnienia i STARTTLS oraz port 465 dla SMTP z TLS od początku połączenia, ale poprawne ustawienie zawsze trzeba potwierdzić u operatora skrzynki.
Metoda login() korzysta z mechanizmów uwierzytelniania ogłoszonych przez serwer w odpowiedzi na EHLO. Nie każda usługa dopuszcza zwykłe hasło do konta; dostawca może wymagać hasła aplikacyjnego, tokenu albo innego sposobu autoryzacji. Błąd logowania nie oznacza więc automatycznie problemu w samym Pythonie. Warto sprawdzić adres serwera, port, wymagany tryb TLS, nazwę użytkownika, metodę uwierzytelniania oraz to, czy konto ma włączoną możliwość wysyłania przez SMTP.
Budowa wiadomości i przekazanie jej do serwera
Do przygotowania wiadomości wygodnie służą klasy z pakietu email, między innymi EmailMessage. Obiekt wiadomości może zawierać nagłówki takie jak From, To i Subject, a treść ustawia się na przykład przez set_content(). Dla wiadomości wieloczęściowych można dodać wersję HTML oraz załączniki. Jest to bezpieczniejsze i czytelniejsze niż ręczne składanie całego tekstu SMTP, ponieważ klasy modułu email zajmują się między innymi kodowaniem nagłówków i formatem MIME.
send_message() przyjmuje obiekt wiadomości przygotowany przez moduł email. Alternatywnie sendmail() przekazuje nadawcę, odbiorców i surową treść wiadomości. Adresy przekazane jako odbiorcy w wywołaniu metody decydują o komendach SMTP RCPT TO; nagłówek To jest częścią treści wyświetlanej odbiorcy i nie powinien być jedynym źródłem listy adresów. Z tego powodu przy wielu odbiorcach trzeba poprawnie zbudować zarówno nagłówki, jak i listę adresatów przekazywaną klientowi.
Po wysłaniu wiadomości serwer może zaakceptować jednych odbiorców, a odrzucić innych. Wynik sendmail() ma postać słownika opisującego adresy, dla których serwer zwrócił błąd, dlatego brak wyjątku nie zawsze oznacza skuteczne przyjęcie każdego odbiorcy. Problemy mogą wynikać również z odrzucenia nadawcy, braku uprawnień do użycia wskazanego adresu From, limitu wysyłki, błędnego formatu adresu albo polityki serwera. Po zakończeniu pracy połączenie należy zamknąć przez quit(); praktycznym rozwiązaniem jest użycie klienta jako menedżera kontekstu w instrukcji with.
Obsługa wyjątków i serwisowe sprawdzanie wysyłki
Moduł smtplib definiuje wyjątki związane między innymi z problemem połączenia, odpowiedzią serwera i błędami SMTP. W kodzie diagnostycznym warto rozróżniać brak możliwości połączenia, przekroczenie czasu oczekiwania, nieudaną negocjację TLS, odrzucenie uwierzytelnienia oraz błędy zwrócone dla konkretnych odbiorców. Pomaga w tym ustawienie rozsądnego parametru timeout oraz rejestrowanie kodu odpowiedzi i etapu sesji, bez zapisywania hasła lub tokenu w logach.
Jeżeli skrypt nie wysyła wiadomości, należy sprawdzić kolejno rozwiązywanie nazwy serwera, dostępność wskazanego portu, zgodność trybu SMTP lub SMTP_SSL z wymaganiami dostawcy, poprawność certyfikatu oraz wynik login(). Przy STARTTLS trzeba upewnić się, że starttls() wykonuje się przed uwierzytelnieniem. Warto też sprawdzić zegar systemowy, ponieważ znaczna rozbieżność czasu może powodować problemy z weryfikacją certyfikatu TLS. Dodatkowym tropem są odpowiedzi serwera po komendach MAIL FROM i RCPT TO, ponieważ pokazują, czy odrzucenie nastąpiło przed przekazaniem treści wiadomości.
Warszawskie Pogotowie Komputerowe zajmuje się profesjonalną naprawą laptopów, komputerów PC i ich podzespołów, a w ramach diagnostyki oprogramowania można również sprawdzić konfigurację środowiska Pythona, certyfikatów oraz programu odpowiedzialnego za wysyłkę. Taka kontrola pozwala oddzielić awarię komputera lub systemu od błędnej konfiguracji konta pocztowego, nieprawidłowego portu albo ograniczeń narzuconych przez serwer SMTP.