submit_sm (command_id 0x00000004) sends a mobile-terminated message from the ESME to the SMSC. Its body is a fixed sequence of mandatory fields — addressing (TON/NPI + address), esm_class, protocol_id, priority_flag, scheduling, registered_delivery, data_coding, sm_length and short_message — optionally followed by TLVs. submit_sm_resp returns the SMSC message_id.
bind_transceiverOpen and authenticate the sessionbind_transceiver_respSession acceptedsubmit_smSend a messagesubmit_sm_respAccepted, message ID returneddeliver_smDelivery receipt or inbound messagedeliver_sm_respAcknowledgedenquire_linkKeepalive while idle
The full mandatory field order
submit_sm's body is a fixed, ordered sequence — there are no field tags, so order and size are everything. The table lists all mandatory parameters in wire order. short_message may be empty when the text is carried in a message_payload TLV instead; do not populate both.
| # | Field | Type | Notes |
|---|---|---|---|
| 1 | service_type | C-Octet String (6) | Service category; usually empty |
| 2 | source_addr_ton | Integer (1) | Type of number of the sender |
| 3 | source_addr_npi | Integer (1) | Numbering plan of the sender |
| 4 | source_addr | C-Octet String (21) | Sender address / alphanumeric ID |
| 5 | dest_addr_ton | Integer (1) | Type of number of the recipient |
| 6 | dest_addr_npi | Integer (1) | Numbering plan of the recipient |
| 7 | destination_addr | C-Octet String (21) | Recipient MSISDN |
| 8 | esm_class | Integer (1) | Message mode + type + UDHI flag |
| 9 | protocol_id | Integer (1) | GSM TP-PID; usually 0 |
| 10 | priority_flag | Integer (1) | 0 (normal) – 3 (highest) |
| 11 | schedule_delivery_time | C-Octet String (1|17) | Empty = immediate |
| 12 | validity_period | C-Octet String (1|17) | Empty = SMSC default |
| 13 | registered_delivery | Integer (1) | Request delivery receipt |
| 14 | replace_if_present_flag | Integer (1) | 0 = no, 1 = replace |
| 15 | data_coding | Integer (1) | Encoding / DCS |
| 16 | sm_default_msg_id | Integer (1) | Canned message id; usually 0 |
| 17 | sm_length | Integer (1) | Length of short_message (0–254) |
| 18 | short_message | Octet String (0–254) | The message payload |
Addressing: TON and NPI
source_addr and destination_addr each carry a Type of Number (TON) and Numbering Plan Indicator (NPI). For an international MSISDN use TON 1 (International) with NPI 1 (ISDN/E.164). For an alphanumeric sender ID use TON 5 (Alphanumeric) — the source_addr then holds up to 11 GSM-7 characters. Getting TON/NPI wrong is a leading cause of undelivered or mis-routed traffic.
| TON | Meaning | NPI | Meaning |
|---|---|---|---|
| 0 | Unknown | 0 | Unknown |
| 1 | International | 1 | ISDN (E.163/E.164) |
| 2 | National | 3 | Data (X.121) |
| 3 | Network specific | 4 | Telex (F.69) |
| 4 | Subscriber number | 6 | Land Mobile (E.212) |
| 5 | Alphanumeric | 8 | National |
| 6 | Abbreviated | 9 | Private |
esm_class
esm_class is a bit-field that sets the messaging mode, the message type and GSM-specific features. The most important bit for senders is UDHI (0x40): set it when short_message begins with a User Data Header, for example a concatenation header. bit 0x80 requests the GSM reply path.
| Bits | Field | Value → meaning |
|---|---|---|
| 1–0 | Messaging mode | 0 default · 1 datagram · 2 forward · 3 store & forward |
| 5–2 | Message type | 0 default · 0x04 delivery receipt · 0x08 delivery ack · 0x10 user ack |
| 6 | UDHI | 0x40 = short_message begins with a UDH |
| 7 | Reply path | 0x80 = set GSM reply path |
data_coding, registered_delivery and validity
data_coding selects the text encoding: 0x00 = SMSC default (typically GSM 7-bit), 0x04 = 8-bit binary, 0x08 = UCS-2 for Unicode. registered_delivery's low two bits control receipts: 0 = none, 1 = receipt on final success or failure, 2 = on failure only. validity_period and schedule_delivery_time use the absolute form YYMMDDhhmmsstnnp or a relative form; an empty string means immediate delivery and the SMSC's default validity. Keep validity_period tight for OTPs so a delayed code expires rather than arriving stale.
| Value | Encoding |
|---|---|
| 0x00 | SMSC default alphabet (usually GSM 7-bit) |
| 0x03 | Latin-1 (ISO-8859-1) |
| 0x04 | 8-bit binary (octet-unspecified) |
| 0x08 | UCS-2 (UTF-16BE) — Unicode |
The response
submit_sm_resp (0x80000004) returns command_status and, on success, a message_id (C-Octet String, up to 65 chars) that the SMSC assigns to the message. Store it: it is the key you match against the receipted_message_id in the delivery receipt. Beware format drift — some SMSCs return the id in hex on submit and decimal in the DLR, so normalise both when correlating.
Frequently asked
What TON/NPI do I use for an alphanumeric sender ID?
Use source_addr_ton = 5 (Alphanumeric) and source_addr_npi = 0 (Unknown). The source_addr then holds up to 11 GSM-7 characters. Alphanumeric sender IDs are display-only and cannot receive replies.
How do I request a delivery receipt in submit_sm?
Set registered_delivery = 1 to get a receipt on final delivery or failure, or 2 for failure only. Request receipts only where you actually consume them, since unread DLRs waste throughput.
What is the maximum length of short_message?
The short_message field holds up to 254 octets, with sm_length giving the exact count. For longer text, either segment with a UDH across multiple submit_sm PDUs or carry the whole payload in the message_payload TLV instead of short_message.
Can I set both short_message and message_payload?
No. Populate one or the other. Providers reject a submit_sm that carries the message in both the mandatory short_message field and the message_payload TLV.
How do I send a Unicode message?
Set data_coding = 0x08 (UCS-2) and encode the text as UTF-16 big-endian in short_message. A single UCS-2 SMS holds 70 characters; longer Unicode text is segmented at 67 characters per part.
Source specifications
The published standards this page is grounded in. Opens in a new tab.