SMS z polskimi znakami: dlaczego tylko 70 znaków?

SMS mieści 160 znaków tylko wtedy, gdy każdy znak należy do alfabetu GSM-7. Wystarczy jedna polska litera (ą, ć, ę, ł, ń, ó, ś, ź, ż), emotka albo „drukarski” cudzysłów, a cała wiadomość przechodzi na kodowanie UCS-2, w którym jeden SMS ma 70 znaków, a dłuższe wiadomości dzielą się co 67 znaków zamiast co 153. Operatorzy i bramki liczą opłatę za każdą część, więc jeden znak potrafi podwoić koszt wysyłki.
Dlaczego SMS ma 160 znaków, a z polskimi znakami tylko 70?
Bo jedna część SMS-a ma stały ładunek 140 bajtów (1120 bitów), a kodowanie decyduje, ile znaków się w nim zmieści. GSM-7 zapisuje znak na 7 bitach, więc 1120 ÷ 7 = 160 znaków; UCS-2 używa 16 bitów na znak, więc 1120 ÷ 16 = 70 znaków.
Dokumentacja AWS End User Messaging SMS mówi to wprost: wiadomość złożona wyłącznie ze znaków zestawu GSM 03.38 może mieć do 160 znaków, a wiadomość z dowolnym znakiem spoza niego – do 70. To przełączenie działa na zasadzie „wszystko albo nic”. Kodowanie wybiera się dla całej wiadomości, nie dla pojedynczych znaków, więc 159 zwykłych liter i jedno „ł” wysyłasz w całości w UCS-2.
Domyślny, 7-bitowy alfabet SMS ze standardu GSM. Obejmuje litery łacińskie A–Z i a–z, cyfry, typowe znaki interpunkcyjne, kilka liter zachodnioeuropejskich (np. é, ä, ö, ü, ñ, à) i część wielkich liter greckich. Nie ma w nim żadnej polskiej litery diakrytycznej.
Stałe, 16-bitowe kodowanie Unicode, którego telefon i bramka używają, gdy wiadomość zawiera choć jeden znak spoza GSM-7. Obsłuży niemal każde pismo, ale w jednej części zmieści mniej niż połowę znaków.
Dlaczego długie SMS-y dzielą się co 153 i co 67 znaków?
Gdy wiadomość nie mieści się w jednej części, każda część dostaje nagłówek UDH (User Data Header), dzięki któremu telefon składa je w całość – a nagłówek zabiera miejsce na tekst. W GSM-7 kosztuje 7 znaków, więc zostaje 153 na część; w UCS-2 kosztuje 3 znaki, więc zostaje 67.
Twilio podaje te same liczby: 160 znaków dla pojedynczej części GSM-7, 153 na część w wiadomości wieloczęściowej, 70 dla pojedynczej części UCS-2 i 67 na każdą kolejną.
W praktyce SMS o długości 161 znaków to nie „jeden SMS i jeden znak”. To dwie części po maksymalnie 153 znaki, a pojemność dwóch części to 306 znaków, nie 320. Tabela pokazuje, od której długości zaczyna się kolejna część.
| Liczba części (płatnych SMS-ów) | Maks. długość GSM-7 (znaki) | Maks. długość UCS-2 (znaki) |
|---|---|---|
| 1 | 160 | 70 |
| 2 | 306 | 134 |
| 3 | 459 | 201 |
| 4 | 612 | 268 |
| 5 | 765 | 335 |
| 10 | 1530 | 670 |
Wyliczone dla 160/153 i 70/67 znaków na część. Stan na listopad 2026.
Dostawcy ograniczają też całkowitą długość. SMSAPI przyjmuje do 1530 znaków (670 ze znakami specjalnymi) w maksymalnie 10 częściach i zaznacza, że polskie litery to znaki specjalne. AWS przyjmuje 1530 znaków GSM albo 630 znaków spoza GSM, a Twilio podaje 1600 i 700 i zaleca, by SMS nie przekraczał 320 znaków. Sprawdź limit swojego dostawcy, zanim zbudujesz długie szablony.
Które znaki przełączają SMS na Unicode (UCS-2)?
Każdy znak, którego nie ma w tabeli GSM 03.38. W polskich wiadomościach winowajcy to prawie zawsze trzy grupy: litery z ogonkami i kreskami, znaki typograficzne wstawiane przez edytory tekstu oraz emotki.
Pełną tabelę GSM 03.38 publikuje AWS. Zestawienie z alfabetami kilku języków pokazuje, dlaczego ta sama kampania kosztuje jedną część po niemiecku i dwie po polsku:
| Język | Litery, które zostają w GSM-7 | Litery, które wymuszają UCS-2 |
|---|---|---|
| polski | żadna z polskich liter diakrytycznych | ✗ ą ć ę ł ń ó ś ź ż i ich wielkie odpowiedniki |
| niemiecki | ✓ ä ö ü ß Ä Ö Ü | żadna ze standardowych liter |
| hiszpański | ~ ñ Ñ é É ü Ü ¿ ¡ | ✗ á í ó ú Á Í Ó Ú |
| angielski | ✓ wszystkie litery | cudzysłowy drukarskie, półpauza, pauza, wielokropek |
Na podstawie tabeli znaków GSM 03.38 opublikowanej przez AWS. Stan na listopad 2026.
Najwięcej niespodzianek robią znaki, których nikt świadomie nie wpisał:
- Cudzysłowy i apostrofy drukarskie („ ” ’): Word, Dokumenty Google i macOS zamieniają proste cudzysłowy automatycznie. AWS pokazuje 130-znakową wiadomość, która wymaga dwóch części tylko przez jeden apostrof ’ w „Dr. Salazar’s”.
- Półpauza, pauza i wielokropek (– — …): zwykły dywiz (-) jest w GSM-7, półpauza i wielokropek jako jeden znak – nie.
- Niewidoczne znaki: twarda spacja albo spacja o zerowej szerokości skopiowana ze strony lub z CMS-a wygląda jak zwykła spacja, ale wymusza UCS-2.
- Emotki: żadnej nie ma w GSM-7. Według Twilio emotka zajmuje 2 z 70 znaków części UCS-2, a emotki z modyfikatorami (np. kolorem skóry) jeszcze więcej.
⚠️ Uwaga: Personalizacja zmienia kodowanie osobno dla każdego odbiorcy. „Cześć [[fname]]” to oczywiście UCS-2, ale nawet „Czesc [[fname]]” zostaje w GSM-7 dla Anny i przechodzi na UCS-2 dla Łukasza czy Józefa. Ten sam szablon może więc kosztować jedną część u jednego kontaktu i dwie u drugiego.
Które znaki GSM-7 liczą się jako dwa?
Dziewięć znaków drukowalnych leży w tabeli rozszerzeń GSM-7 i każdy wysyłany jest jako znak ucieczki plus sam znak, więc zajmuje dwa z 160 (lub 153) miejsc: ^ { } \ [ ] ~ | €.
Nie przełączają wiadomości na UCS-2, ale skracają limit. „Cena: 20€ [promocja]” to 20 znaków na ekranie i 23 w GSM-7. W zwykłym tekście różnica jest niewielka, w wiadomościach z kodami, JSON-em czy linkami z nawiasami – spora. Gdy wiadomość jest blisko granicy, pisz „EUR” zamiast „€” albo zamień nawiasy kwadratowe na okrągłe.
Jeśli licznik i tabela kiedyś się nie zgadzają, wierz liczbie części, którą dostawca zwraca po wysyłce – za nią płacisz.
Ile kosztują polskie znaki w SMS-ie?
Każda część to osobno płatny SMS. Twilio pisze, że rozlicza SMS-y za każdą wysłaną część, AWS – za liczbę części, a SMSAPI wysyła długie wiadomości jako maksymalnie 10 połączonych SMS-ów rozliczanych według cennika. Wiadomość, która urosła z jednej do dwóch części, podwaja koszt wysyłki.
Tabela mnoży oficjalne ceny za część przez 1000 odbiorców. To ceny katalogowe SMS-ów wychodzących z publicznych stron dostawców, bez rabatów ilościowych, opłat operatorskich i VAT.
| Dostawca i kraj | Cena za część | 1000 × 1 część | 1000 × 2 części | 1000 × 3 części |
|---|---|---|---|---|
| SMSAPI → Polska (prepaid, najniższy próg) | 0,17 zł netto | 170 zł | 340 zł | 510 zł |
| Twilio → Polska | 0,0457 USD | 45,70 USD | 91,40 USD | 137,10 USD |
| Twilio → Niemcy | 0,112 USD | 112,00 USD | 224,00 USD | 336,00 USD |
| Twilio → Hiszpania | 0,0875 USD | 87,50 USD | 175,00 USD | 262,50 USD |
Ceny Twilio według stron Twilio („current as of October 2026”), cennik SMSAPI sprawdzony w listopadzie 2026. Stan na listopad 2026.
Przykład pokazuje, jak niewiele trzeba. Oba teksty mówią to samo; pierwszy ma 94 znaki z polskimi literami i idzie jako dwie części UCS-2, drugi to te same 94 znaki bez ogonków i mieści się w jednej części GSM-7:
Cześć Anna, Twoje zamówienie 1042 zostało wysłane. Śledź: https://ex.co/t/1042 STOP=rezygnacja
→ UCS-2, 94 znaki, 2 części
Czesc Anna, Twoje zamowienie 1042 zostalo wyslane. Sledz: https://ex.co/t/1042 STOP=rezygnacja
→ GSM-7, 94 znaki, 1 część
Przy 10 000 odbiorców w SMSAPI to różnica między 1700 a 3400 zł netto za jedną wysyłkę – przy tych samych słowach.
Czy wysyłać SMS-y bez polskich znaków?
To zależy od rodzaju wiadomości i od odbiorcy. Usunięcie ogonków (transliteracja) utrzymuje wiadomość w GSM-7 i może obniżyć koszt o połowę, ale pogarsza czytelność i bywa odbierane jako niedbałość – to kompromis, nie reguła.
✅ Zalety
- Do 160 znaków w jednej części zamiast 70; do 153 na część zamiast 67.
- Przewidywalny koszt: imiona z polskimi literami nie wypychają pojedynczych odbiorców do kolejnej części.
- SMS-y transakcyjne bez polskich znaków są w Polsce powszechne, więc odbiorcy są do nich przyzwyczajeni.
❌ Na co uważać
- Niektóre słowa zmieniają znaczenie: „sąd” staje się „sadem”, „łączka” wygląda dziwnie jako „laczka”.
- Marka, która wszędzie dba o język, w SMS-ie bez ogonków może wyglądać niechlujnie.
- Imiona i nazwy miejscowości są zapisane błędnie, co w wiadomościach osobistych razi najbardziej.
Nie musisz usuwać ogonków ręcznie. SMSAPI ma parametr normalize, który zamienia znaki specjalne na odpowiedniki (ą→a, ć→c, ę→e), a według dokumentacji domyślnym kodowaniem jest windows-1250, chyba że przekażesz inne, np. utf-8. Twilio oferuje Smart Encoding, które zamienia część znaków spoza GSM na odpowiedniki i prostuje cudzysłowy.
Rozsądny kompromis: zostaw polskie znaki w krótkich wiadomościach, które i tak mieszczą się w 70 znakach, a transliteruj tylko wtedy, gdy tekst inaczej wymagałby kolejnej części. Cokolwiek wybierzesz, ustal to raz i stosuj konsekwentnie.
Czy link, tekst rezygnacji i nazwa nadawcy się liczą?
Link i tekst rezygnacji liczą się do długości, bo są częścią treści; alfanumeryczna nazwa nadawcy nie, bo jedzie w polu adresu SMS-a, a nie w tekście.
Linki
Pełny adres z parametrami UTM łatwo zajmuje 80–120 znaków, czyli ponad połowę części GSM-7. Używaj krótkiej ścieżki we własnej domenie (np. https://ex.co/t/1042) zamiast długiego linku śledzącego. Krótki link we własnej domenie pokazuje też Twoją markę i nie zależy od zewnętrznego skracacza.
Tekst rezygnacji
Marketingowe SMS-y zwykle zawierają instrukcję rezygnacji; szczegółowe wymogi zależą od kraju. „STOP=rezygnacja” to 15 znaków – uwzględnij je w każdym szablonie od początku, zamiast dopisywać na końcu i odkrywać drugą część. Pisz go bez polskich liter, żeby sam nie przełączał wiadomości na UCS-2. Zasady zgód opisuje poradnik o automatyzacji e-mail i SMS na własnym serwerze. To nie jest porada prawna.
Wstawki personalizacyjne
Imię, numer zamówienia czy kod rabatowy zmieniają końcową długość. Testuj szablony z najdłuższymi realnymi wartościami, a nie z „Ania”, i pamiętaj, że wartość z polską literą zmienia kodowanie dla tego odbiorcy.
Jak sprawdzić liczbę części przed wysyłką?
Przepuść ostateczny tekst, z wypełnionymi wstawkami, przez licznik znający tabelę GSM 03.38, a potem potwierdź wynik u dostawcy na wysyłce testowej. Liczy się liczba części podana przez dostawcę – za nią płacisz.
- Znajdź znaki spoza GSM
Użyj licznika, który pokazuje konkretne znaki wymuszające UCS-2, a nie tylko sumę. Funkcja w Pythonie poniżej robi to offline.
- Testuj z najdłuższymi wartościami
Wypełnij wstawki najdłuższymi imionami i kodami z bazy oraz imionami z polskimi literami.
- Wyślij testowy SMS na swój telefon
Sprawdź, jak wygląda, czy części przychodzą połączone i czy link działa.
- Odczytaj liczbę części u dostawcy
Twilio zwraca
num_segmentsw zasobie wiadomości, SMSAPI –partsi koszt w punktach. Porównaj z szacunkiem przed wysyłką do całej listy.
Funkcja korzysta z tabeli GSM 03.38 z dokumentacji AWS, liczy znaki rozszerzeń podwójnie, a emotki jako dwie jednostki UCS-2. To szacunek: bramki mogą nie dzielić znaku ucieczki ani emotki między dwie części, co przy samej granicy czasem dokłada część.
import math
GSM7_BASIC = set(
"@£$¥èéùìòÇ\nØø\rÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ !\"#¤%&'()*+,-./0123456789:;<=>?"
"¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà"
)
GSM7_EXTENDED = set("\f^{}\\[]~|€") # each costs 2 septets (ESC + char)
def sms_segments(text: str) -> dict:
non_gsm = sorted({c for c in text if c not in GSM7_BASIC | GSM7_EXTENDED})
if not non_gsm:
units = sum(2 if c in GSM7_EXTENDED else 1 for c in text)
single, per_part, encoding = 160, 153, "GSM-7"
else:
units = len(text.encode("utf-16-le")) // 2 # emoji = 2 units
single, per_part, encoding = 70, 67, "UCS-2"
parts = 1 if units <= single else math.ceil(units / per_part)
return {"encoding": encoding, "units": units, "parts": parts,
"non_gsm": non_gsm}
if __name__ == "__main__":
import sys
print(sms_segments(sys.stdin.read().rstrip("\n")))
Zapisz ją jako sms_segments.py i przekaż wiadomość na wejście:
echo "Zażółć gęślą jaźń" | python3 sms_segments.py
# {'encoding': 'UCS-2', 'units': 17, 'parts': 1, 'non_gsm': ['ó', 'ą', 'ć', 'ę', 'ł', 'ń', 'ś', 'ź', 'ż']}
Lista non_gsm pokazuje dokładnie, który znak zamienić.
📋 Checklist
- Brak cudzysłowów drukarskich, półpauz, wielokropków i twardych spacji z edytora
- Decyzja: polskie znaki zostają czy transliteracja
- Znaki rozszerzeń (€ [ ] { } \ ~ ^ |) policzone podwójnie
- Tekst rezygnacji i krótki link wliczone w długość
- Szablon przetestowany z najdłuższymi wartościami wstawek
- Liczba części potwierdzona u dostawcy na wysyłce testowej
Liczba części SMS-ów wysyłanych z NetSendo
NetSendo wysyła SMS-y przez Twilio, Vonage, MessageBird, Plivo albo SMSAPI, a opisane zasady dzielenia na części to zasady dostawcy, nie NetSendo. W praktyce liczą się dwie rzeczy.
Po pierwsze, licznik w edytorze SMS to szybki szacunek. Oznacza wiadomość jako Unicode, gdy tylko pojawi się dowolny znak spoza ASCII, i dzieli długość przez 160 albo 70. Niemiecki tekst z „ü” zobaczysz więc jako Unicode, choć GSM-7 ma „ü”, a wiadomości tuż nad granicą części mogą zostać policzone o jedną część za mało, bo licznik nie stosuje reguły 153/67. Traktuj go jak kontrolkę ostrzegawczą, a teksty graniczne sprawdzaj funkcją powyżej.
Po drugie, prawdziwą liczbę dostajesz po wysyłce. Webhook sms.sent zawiera pola parts i credits dla każdej wiadomości, wzięte z odpowiedzi dostawcy (w SMSAPI parts i punkty, w Twilio num_segments). Możesz je zbierać w n8n przez node NetSendo albo dowolnym endpointem opisanym w dokumentacji webhooków, zweryfikować podpis HMAC-SHA256 i dostać alert, gdy kampania ma średnio więcej części, niż planowałeś. NetSendo wysyła do SMSAPI z encoding=utf-8, więc polskie znaki dochodzą tak, jak je napisałeś; jeśli chcesz je usunąć, zrób to w treści. SMS-y wyślesz też przez REST API.
ℹ️ Uwaga: Wysyłka SMS w starszych wersjach NetSendo nie działała; wersja 2.2.0 naprawiła zadanie wysyłki SMS, a 2.7.2 kampanie wysyłane z panelu i testowy SMS. Zanim oprzesz się na SMS-ach, zaktualizuj NetSendo do bieżącej wersji.
🎯 Rady eksperta
Szablony twórz w edytorze kodu albo bezpośrednio w edytorze SMS, nigdy w Wordzie czy Dokumentach Google, które same wstawiają „drukarskie” cudzysłowy i półpauzy.
Zostaw miejsce na tekst rezygnacji i dłuższe wartości wstawek, żeby długie imię nie dokładało części.
Z polskimi literami piszesz na 70 znaków; bez nich – na 160. Obie drogi są w porządku, byle konsekwentne.
Porównaj średnią liczbę części na wiadomość z planem. Skok zwykle oznacza, że do szablonu wkradł się znak spoza GSM.
Najczęściej zadawane pytania
Dlaczego SMS z polskimi znakami ma tylko 70 znaków?
Żadna polska litera diakrytyczna nie należy do alfabetu GSM-7, więc jedna litera ą, ł czy ś przełącza całą wiadomość na kodowanie UCS-2. UCS-2 zapisuje znak na 16 bitach, więc w 140 bajtach jednej części mieści się 70 znaków.
Ile znaków ma SMS z polskimi znakami składający się z kilku części?
67 znaków na część, bo każda część zawiera nagłówek łączący. Dwie części mieszczą więc 134 znaki, trzy – 201.
Czy emotka w SMS-ie liczy się jako jeden znak?
Nie. Emotka przełącza wiadomość na UCS-2 i według Twilio zajmuje 2 z 70 znaków części; emotki z modyfikatorami zajmują więcej.
Czy lepiej wysyłać SMS-y bez polskich znaków?
Bez polskich znaków wiadomość zostaje w GSM-7 i mieści do 160 znaków, co może obniżyć koszt o połowę. Kosztem jest gorsza czytelność i wygląd, więc to decyzja zależna od rodzaju wiadomości i marki.
Które znaki liczą się w SMS-ie podwójnie?
Znaki z tabeli rozszerzeń GSM-7: ^ { } \ [ ] ~ | oraz €. Każdy zajmuje dwa miejsca, ale nie przełącza wiadomości na UCS-2.
Czy SMSAPI może samo usunąć polskie znaki?
Tak, parametr normalize=1 zamienia znaki specjalne na odpowiedniki, np. ą na a i ć na c. Domyślnym kodowaniem SMSAPI jest windows-1250, chyba że przekażesz inne.
Źródła
- Twilio: What is the SMS character limit?
- Twilio Support: Can I send and receive emoji with Twilio?
- AWS End User Messaging SMS: SMS character limits and GSM 03.38 character set
- SMSAPI documentation (message, encoding, normalize, max_parts)
- SMSAPI price list
- Twilio SMS pricing: Poland
- Twilio SMS pricing: Germany
- Twilio SMS pricing: Spain
Wysyłaj e-maile i SMS-y z własnego serwera
NetSendo działa na Twojej infrastrukturze i łączy się z dostawcą SMS, którego już używasz.




