Character encoding and message length
Which characters fit the GSM 03.38 alphabet, when a message switches to Unicode, how long messages are split into parts, and how to URL-encode text.
Send all text as UTF-8. Wire2Air then delivers each message in one of two encodings:
- GSM 03.38 (the GSM 7-bit default alphabet), when every character in the message is in it.
- Unicode (UCS-2), as soon as one character is not. The whole message switches, not just that character.
The encoding decides how many characters fit in one message, and so how many credits a message uses.
GSM 03.38 alphabet
GSM 03.38 covers the Latin alphabet, digits, common punctuation, some accented letters and a few Greek capitals. The basic table has 128 positions; each character counts as one:
| 0x00 | 0x10 | 0x20 | 0x30 | 0x40 | 0x50 | 0x60 | 0x70 | |
|---|---|---|---|---|---|---|---|---|
| 0x0 | @ | Δ | space | 0 | ¡ | P | ¿ | p |
| 0x1 | £ | _ | ! | 1 | A | Q | a | q |
| 0x2 | $ | Φ | " | 2 | B | R | b | r |
| 0x3 | ¥ | Γ | # | 3 | C | S | c | s |
| 0x4 | è | Λ | ¤ | 4 | D | T | d | t |
| 0x5 | é | Ω | % | 5 | E | U | e | u |
| 0x6 | ù | Π | & | 6 | F | V | f | v |
| 0x7 | ì | Ψ | ' | 7 | G | W | g | w |
| 0x8 | ò | Σ | ( | 8 | H | X | h | x |
| 0x9 | Ç | Θ | ) | 9 | I | Y | i | y |
| 0xA | line feed | Ξ | * | : | J | Z | j | z |
| 0xB | Ø | escape | + | ; | K | Ä | k | ä |
| 0xC | ø | Æ | , | < | L | Ö | l | ö |
| 0xD | carriage return | æ | - | = | M | Ñ | m | ñ |
| 0xE | Å | ß | . | > | N | Ü | n | ü |
| 0xF | å | É | / | ? | O | § | o | à |
Extended characters
Ten more characters are sent as the escape code (0x1B) followed by a second code, so each counts as two:
| Character | Codes (hex) | Codes (decimal) |
|---|---|---|
€ | 1B 65 | 27, 101 |
| form feed | 1B 0A | 27, 10 |
[ | 1B 3C | 27, 60 |
\ | 1B 2F | 27, 47 |
] | 1B 3E | 27, 62 |
^ | 1B 14 | 27, 20 |
{ | 1B 28 | 27, 40 |
| | 1B 40 | 27, 64 |
} | 1B 29 | 27, 41 |
~ | 1B 3D | 27, 61 |
A line break written as \r\n (carriage return + line feed) is two basic characters, so it counts as two.
Unicode
If a message contains any character outside the two tables above (for example Chinese, Arabic or Japanese text, emoji, or typographic quotes), the whole message is sent as Unicode. Unicode allows any language, but fits fewer characters in each message.
Not every handset or carrier displays every Unicode character.
Message length
One SMS holds 160 GSM characters or 70 Unicode characters. A longer message is split into parts that the phone joins back together (a concatenated message). Each part loses room to a 7-character header (the User Data Header) that tells the phone how to join them, so a part holds 153 GSM characters or 67 Unicode characters.
| Parts | GSM 03.38, total characters | Unicode, total characters |
|---|---|---|
| 1 | 160 | 70 |
| 2 | 306 | 134 |
| 3 | 459 | 201 |
| 4 | 612 | 268 |
| 5 | 765 | 335 |
| 6 | 918 | 402 |
Up to six parts can form one long message. Each part is billed as one message.
Keep messages in GSM
A single typographic character switches a message to Unicode and cuts it from 160 to 70 characters. Text pasted from a word processor is the usual cause. Replace:
| Instead of | Use |
|---|---|
‘ ’ (curly apostrophes) and ` | ' |
“ ” (curly quotes) | " |
– — (dashes) and ¬ | - |
… | ... |
~, | and the other extended characters stay in GSM but count as two each.
The dashboard's Unicode Detect tool replaces common Unicode characters with GSM equivalents.
URL encoding
Parameters must be URL-encoded (percent-encoded): reserved characters such as &, /, ? and spaces, and every non-ASCII character, become % codes. Without encoding, an & in your text ends the parameter early.
text=A sample text & Message
text=A%20sample%20text%20%26%20Message
Every HTTP library does this for you. Pass parameters as a map or dictionary rather than building the string by hand:
- Python 3:
urllib.parse.urlencode() - Node:
URLSearchParams - PHP:
http_build_query()(orurlencode()for a single value) - C#:
FormUrlEncodedContent, orUri.EscapeDataString()for a single value - cURL:
--data-urlencode
Encode each value once. Encoding a value and then handing it to a library that encodes again sends %2520 instead of a space.

