Biblioteka Python SMS API

A teraz coś z zupełnie innej beczki! Nadszedł czas na omówienie kolejnej biblioteki programistycznej do kampanii SMS. Została ona napisana w specyficznym i powszechnie lubianym języku. Coś dla tych, którzy lubią brytyjski humor i szybkie skrypty, ale nie lubią nawiasów klamrowych. Poznaj naszą bibliotekę Python!

Na początek skieruję Cię do odpowiedniego repozytorium SMSAPI na GitHub, gdzie znajdziesz kod produkcyjny, testy i przykłady. Dokładne analizowanie plik po pliku nie będzie jednak konieczne. Poniżej przybliżę najważniejsze funkcjonalności biblioteki, dzięki którym obsłużysz wysyłkę SMS.

Niejednokrotnie będę się odwoływał do Dokumentacji API, która dokładnie opisuje komunikację między dowolną aplikacją a serwerem. 

Biblioteka Python: instalacja i konfiguracja wysyłki SMS

Przed rozpoczęciem kodowania trzeba przygotować kilka rzeczy. Przede wszystkim, zainstaluj bibliotekę. Jest ona hostowana poza GitHubem, na serwisie PyPI (Python Package Index). Dzięki temu instalacja za pomocą menedżera pakietów pip jest błyskawiczna:

pip install smsapi-client

Podobnie jak w bibliotekach SMSAPI w innych językach, Twój program będzie komunikował się z serwerem dzięki metodom HTTP: GET, PUT, POST i DELETE. Obsługuje je zewnętrzna biblioteka Requests, która jest wymagana do instalacji. Będzie ona działać „na zapleczu” gotowej aplikacji, więc spokojnie – nie musisz wcale znać się na protokołach sieciowych, aby programowo zarządzać kampaniami SMS

Załóż konto SMSAPI

Jest jeszcze jedno, co musisz zrobić, aby wysyłać powiadomienia SMS w Pythonie: założyć i skonfigurować konto SMSAPI! Poniżej znajdziesz szybki poradnik.

Dzięki temu rozpoczniemy współpracę i będziesz mógł korzystać z całego SMS API. Pamiętaj też, aby uzupełnić niezbędne informacje:

  • dane osobowe: imię i nazwisko, adres e-mail i hasło, numer telefonu;
  • dane Twojej firmy – do wystawiania faktur;
  • pole nadawcy SMS, o którym przeczytasz dalej;
  • przydadzą się też: e-mail do wysyłania faktur i kontakt do Twojej księgowości.

Następnie, w Panelu Klienta wygeneruj token autoryzacyjny OAuth 2. To swoisty klucz kryptograficzny. Dzięki niemu program będzie mógł uzyskać dostęp do zasobów serwera SMSAPI. Token możesz wkleić do skryptu lub umieścić we własnym pliku konfiguracyjnym.

Przygotowania zakończone! Zobaczmy teraz, jak wygląda początek pracy z kodem w Pythonie.

Biblioteka SMS Python: prosta wysyłka wiadomości

Jedną z największych zalet Pythona jest prostota. W tym języku skrypty mogą być zwięzłe i przejrzyste, a zarazem zaawansowane, a omawiana biblioteka nie stanowi wyjątku. Zlecenie prostej wysyłki pojedynczego SMS-a wygląda następująco:

from smsapi.client import SmsApiPlClient

token = '0000000000000000000000000000000000000000'
client = SmsApiPlClient(access_token=token)
result = client.sms.send(to='+48111222333', message='Hello world!')

Co tu się konkretnie dzieje? Najpierw tworzona jest instancja klienta, która zarządza połączeniem z serwerem – dlatego potrzebujesz tokena. Formułowanie zapytań do serwera należy do szczegółów implementacji komunikacji z API, które ogarnia za Ciebie biblioteka.

Klient będzie używany za każdym razem, ponieważ zawiera obiekty odpowiedzialne za wszystkie funkcjonalności. Następna linijka odwołuje się po prostu do obiektu sms i zleca wysyłkę zadanej wiadomości na dany numer telefonu. Tylko tyle!

Funkcja send może przyjmować wiele argumentów, które na różne sposoby modyfikują wysyłkę. Opisuje je dział Dokumentacji o pojedynczym SMS, a dalej przeczytasz też o kilku najprzydatniejszych.

Zwracana wartość 'result’ to iterowalny obiekt klasy SmsSendResult, który zawiera parametry wysłanych wiadomości. Są to konkretnie: count, czyli liczba zleconych wysyłek i results – lista słowników, które odpowiadają poszczególnym wiadomościom. Słownik taki zawiera m.in.:

  • id – unikalny identyfikator wiadomości SMS w naszym systemie;
  • points – koszt wiadomości, czyli liczba punktów pobranych z Twojego konta;
  • number – numer odbiorcy;
  • status – status doręczenia (lista statusów w Dokumentacji)
  • date_sent – czas wysłania wiadomości.

Pozostałe pola obiektu SmsSendResult są opcjonalne i obecne pod warunkiem użycia parametru details=1:

  • message – treść wiadomości;
  • length – jej długość;
  • parts – na ile części została podzielona.

Wysyłka wielu SMS naraz w bibliotece Python

Twoje kampanie SMS nie obędą się bez możliwości wysyłania wiadomości do wielu odbiorców jednocześnie. Nic prostszego! Zamiast pojedynczego numeru telefonu wystarczy podać ich listę:

from smsapi.client import SmsApiPlClient

token = '0000000000000000000000000000000000000000'
client = SmsApiPlClient(access_token=token)
receivers = ['+48111222333', '+48444555666']

results = client.sms.send(to=receivers, message='Hello receivers!')
for result in results:
	print(result)

Jak wspomniałem, obiekt zwracany przez zlecenie wysyłki jest iterowalny, dlatego powyższa pętla for wypisze na konsoli informacje o poszczególnych wiadomościach. 

W Panelu klienta odnajdziesz możliwość tworzenia grup odbiorców, co ułatwia zorganizowanie wysyłki. Dzięki innej metodzie można skorzystać z tego ułatwienia w kodzie:

from smsapi.client import SmsApiPlClient

token = '0000000000000000000000000000000000000000'
client = SmsApiPlClient(access_token=token)


client.sms.send_to_group(
	group='Group_name', 
	message='Hello group!')

Parametry to oraz group są kierowane do tego samego odwołania do serwera. Są jednak rozłączne, ich jednoczesne użycie wywoła błąd API. Dlatego biblioteka posiada dla nich odrębne funkcje.

Dodatkowe funkjonalności bramki SMS Python

Jak już wspomniałem, wysyłkę można modyfikować poprzez ustawienie czasu dostarczenia, własnego pola nadawcy SMS i personalizację treści.

1. Planowanie wysyłki SMS

Właściwy moment dostarczenia wiadomości jest kluczowy dla przyciągnięcia uwagi odbiorcy, o czym szerzej możesz poczytać w artykule o planowaniu SMS.

Żeby wcielić w życie harmonogram Twojej kampanii, użyj parametru date. Zaplanowanie wysyłki na 1 grudnia 2021 o 12:30, przy pomocy standardowego obiektu datetime wygląda tak:

from smsapi.client import SmsApiPlClient
from datetime import datetime

token = '0000000000000000000000000000000000000000'
client = SmsApiPlClient(access_token=token)
send_time = datetime(2021,12,1,12,30).isoformat()

response = client.sms.send(
	to='+48111222333', 
	message='Hello in the future!',
	date=send_time)

Akceptowane formaty daty to albo czas uniksowy (liczba sekund od 1 stycznia 1970), albo ISO 8601 (czyli tutaj: 2021-12-01T12:30:00+01:00).

Powyższy przykład korzysta z tej drugiej opcji, stąd użycie metody isoformat(). Jeżeli plany się zmienią, możesz anulować już ustaloną wysyłkę. Do tego potrzebny jest unikalny identyfikator, który należy zawczasu zapisać. Kontynuując zatem poprzedni listing:

smsIdToCancel = response.results[0].id
client.sms.remove_scheduled(smsIdToCancel)

2. Pole nadawcy SMS zamiast numeru telefonu

Ważną funkcjonalnością jest też pole nadawcy SMS. Chodzi o krótki tekst, który zostanie wyświetlony zamiast numeru telefonu nadawcy. To nazwa Twojej firmy, marki lub produktu – coś, dzięki czemu odbiorca natychmiast skojarzy, kto pisze.

Takie „przedstawienie się” może skutecznie przyciągnąć uwagę potencjalnego klienta. Zwłaszcza że wiele osób codziennie otrzymuje na swoje smartfony po kilkanaście powiadomień. Polami nadawcy możesz zarządzać w odpowiedniej sekcji Pola nadawcy w Panelu Klienta. Aby z któregoś z nich skorzystać w kodzie Pythona, po prostu użyj parametru from:

from smsapi.client import SmsApiPlClient

token = '0000000000000000000000000000000000000000'
client = SmsApiPlClient(access_token=token)

client.sms.send(
	to='+48111222333', 
	message='Hello world!',
	from='sender_name')

Obsługa pola nadawcy SMS w Python

Jak już wspomniałem, pola nadawcy SMS wyświetlane zamiast numeru telefonu, pozwalają przedstawić się odbiorcy. Możesz zarządzać nimi ręcznie w Panelu klienta albo programowo w skrypcie. Umożliwia to klasa Sender, która udostępnia metody:

  • add(name) – dodaje nowe pole;
  • check(name) – zwraca obiekt ze statusem, nazwą i flagą czy to pole jest domyślne;
  • remove(name) – usuwa pole;
  • default(name) – ustawia pole jako domyślne;
  • list() – zwraca listę wszystkich pól.

Użycie tej klasy wygląda analogicznie, jak w przypadku wysyłania SMS-ów. Tak wygląda listowanie, dodanie nowego pola, ustawienie go jako domyślne oraz sprawdzenie:

senderList = client.sender.list()
for senderName in senderList
	print(senderName)

client.sender.add('NewSenderName')
client.sender.default('NewSenderName')
client.sender.check('NewSenderName')

Każde nowe pole nadawcy musi zostać zweryfikowane przez pracownika SMSAPI, aby upewnić się, czy dana nazwa nie jest prawnie zastrzeżona. Poza tym istnieją ograniczenia techniczne: dozwolona długość i znaki. Więcej na ten temat przeczytasz w FAQ technicznym poniżej.

3. Personalizacja SMS

Trzecim ważnym sposobem dopracowania kampanii SMS – obok planowania oraz pól nadawcy – jest personalizacja SMS. Dzięki niej podczas masowej wysyłki każda wiadomość zostanie w pewien sposób zmodyfikowana. Poszczególni odbiorcy poczują się wtedy potraktowani bardziej osobiście.

W praktyce działa to dzięki specjalnym ciągom znaków w treści wiadomości. W poszczególnych wysyłanych SMS-ach te ciągi są podmieniane na docelowy tekst. Ten zaś bierze się albo z uprzednio utworzonej bazy kontaktów, albo z jednego z czterech parametrów dowolnych. Zobacz ten drugi przypadek na uproszczonym przykładzie:

receivers = ['+48111222333', '+48444555666']
client.sms.send(
	to=receivers,
	message='Hello [%1%], your number is [%2%]!',
	param1=['Adam', 'Bert']
	param2=['11', '22'])

W kolejnych wiadomościach pole [%1%] będzie zamieniane na kolejne elementy listy param1, analogicznie stanie się z [%2%] i listą param2. Ostatecznie będą więc wyglądać tak:

Hello Adam, your number is 11!

Hello Bert, your number is 22!

Można to zapisać bardziej elegancko, korzystając z bazy kontaktów:

receivers = ['+48111222333', '+48444555666']
client.sms.send(
	to=receivers,
	message='Hello [%imie%], your number is [%1%]!',
	param1=['11', '22'])

W tym przypadku parametr [%imie%] zostanie zamieniony na imię, przypisane do konkretnego odbiorcy w bazie kontaktów. Takich standardowych pól jest naturalnie więcej: nazwisko, e-mail, miasto i inne, co opisuje Dokumentacja

4. Szablony treści wiadomości SMS

Pewnym ułatwieniem przy wysyłkach masowych są szablony treści SMS. Są to wzory wiadomości, które możesz tworzyć w zakładce szabolny. Dzięki nim oszczędzasz czas na pisaniu takich samych powiadomień wiele razy.

Jeśli zaś dodatkowo skorzystasz w nich z parametrów, otrzymasz modyfikowalne treści. Masz więc zarówno wygodniejszą obsługę, jak i spersonalizowane wiadomości. Wykorzystanie przykładowego szablonu może wyglądać tak: 

PackageSentTemplate: „Cześć [%imie%], Twoje zamówienie zostało wysłane! Nadejdzie w przeciągu [%1%] dni roboczych.” 

receivers = ['+48111222333', '+48444555666']
client.sms.send(
	to=receivers,
	template='PackageSentTemplate',
	param1='4')

Obsługa błędów API

Nastawiając się na najlepsze, warto być przygotowanym na najgorsze. Dlatego obsługa błędów to podstawa. Kiedy po stronie serwera wystąpi błąd przetwarzania danego zapytania, informacja o tym zostanie przesłana zamiast normalnej odpowiedzi. Biblioteka przetworzy ją i podniesie jeden z wyjątków.

Zdefiniowano pięć klas, dziedziczących po Exception. Mają one następującą hierarchię:

  • SmsApiException – klasa nadrzędna, pozwala obsługiwać łącznie wszystkie wyjątki pochodzące z biblioteki SMSAPI. Zawiera wiadomość i opcjonalnie kod błędu.
    • ClientException – wystąpi, jeśli nie podano danych autoryzacyjnych.
    • EndpointException – błędy zgłoszone ze strony serwera – patrz lista kodów niżej.
      • SendException – klasa przypisana do akcji wysyłania wiadomości. W razie użycia błędnych numerów telefonów zawiera listę informacji o nich.
      • ContactsException – wyjątki podczas programowej obsługi bazy kontaktów. 

Najczęściej spotykane kody błędów

W dokumentacji znajdziesz szczegółową listę kodów błędów wraz z objaśnieniami. Najczęściej występujące błędy:

  • 11 – zbyt długa wiadomość lub jej brak;
  • 12 – wiadomość podzielona na więcej części, niż wynosi limit;
  • 13 – niepoprawny numer odbiorcy;
  • 14 – błędne pole nadawcy;
  • 26 – za długi temat wiadomości;
  • 40 – nie istnieje grupa o danej nazwie;
  • 101 – błędny token autoryzacyjny;
  • 103 – za mało środków na koncie, aby wysłać wiadomość;
  • 8, 201, 999 – wewnętrzne błędy serwera. 

Wyjątek EndpointException występuje jeszcze w dwóch sytuacjach. Pierwsza to błędy komunikacji z serwerem. Wtedy kod pochodzi z odpowiedzi HTTP, jak choćby znany błąd numer 404 – nie znaleziono zasobu.

Druga możliwość to użycie nierozpoznanej nazwy parametru, czyli najprawdopodobniej literówka. Na przykład kiedy zamiast „message” napiszesz „massage”. 😉

Dalsze opcje obsługi komunikacji mobilnej w Python

Możliwości omawianej biblioteki sięgają dalej! Warto na koniec wspomnieć o paru z nich np. kampaniach SMS czy zarządzaniu bazą kontaktów.

Wysyłka MMS z Python

Ważne jest wysyłanie wiadomości MMS. Obsługuje się je bardzo prosto:

response = client.mms.send(
	to='+48111222333', 
	smil=SMIL_contents,
	subject='Hello multimedia')

Obowiązkowy parametr smil to poprawna treść multimedialna w XML-owym formacie SMIL 1.0, którą musisz uprzednio przygotować. Zwracany jest obiekt tego samego typu, co w przypadku SMS: SmsSendResult. Dodatkowo można podać tekstowy temat wiadomości.

Zarządzanie bazą kontaktów

W artykule napomknąłem też o bazie kontaktów. W prowadzeniu akcji marketingowych posiadanie takiej listy potencjalnych klientów jest absolutnie kluczowe.

SMSAPI pozwala w praktyce wykorzystać bazę danych osobowych do prowadzenia kampanii SMS. W Panelu klienta możesz taką bazą zarządzać, ale biblioteka Python również to umożliwia.

Klasa client posiada obok obiektów sms, sender i mms jeszcze instancję contacts. Sposób użycia tego ostatniego jest więc analogiczny, jak w przykładach, które podawałem wcześniej. Jak choćby utworzenie nowego kontaktu:

response = client.contacts.create_contact(
	first_name='Jan',
	last_name='Kowalski',
	phone_number='+48111222333',
	email='jankowalski@example.com',
	gender='male'
	birthday_date='2000-01-31')

Poszczególne funkcje pozwalają odczytywać, listować, tworzyć, edytować oraz usuwać zarówno poszczególne kontakty, jak i całe grupy. Jest też możliwość przypisania i usunięcia kontaktu z grupy.

Biblioteka Python SMS: podsumowanie

I to wszystko, jeśli chodzi o podstawowe funkcjonalności wysyłania SMS w Python! A jednak, ten artykuł wciąż nie wyczerpał wszystkich możliwości biblioteki.

Więcej próbek zastosowań różnych funkcjonalności znajdziesz w katalogu przykładów na GitHubie. W repozytorium jest też folder testów jednostkowych, napisanych we frameworku unittest. One również mogą posłużyć za źródło przykładowych zastosowań różnych metod.

Zaś wielokrotnie przywoływana Dokumentacja API to źródło wiedzy o znaczeniu poszczególnych parametrów, statusów i kodów. Teraz masz już wiedzę potrzebną do zintegrowania Python z SMS. Do dzieła!

Kilka słów o autorze

Zdjęcie pytona autorstwa David Clode opublikowane na Unsplash.