better-smpp
Client

Sending messages

submitSm with automatic concatenation, encodings, and the other operations.

submitSm

const result = await client.submitSm({
  destinationAddr: "46709771337",
  shortMessage: "Hello!",
  registeredDelivery: 1, // request a delivery receipt
});

submitSm resolves with a SubmitResult:

interface SubmitResult {
  messageId: string | undefined; // id of the first (or only) segment
  messageIds: string[];          // all segment ids, in order
  segments: number;              // how many submit_sm PDUs were sent
  responses: SubmitSmRespPdu[];  // every response, in order
}

It rejects with SmppCommandError on any non-ESME_ROK response.

Automatic concatenation

Text longer than one message is split transparently — 160 GSM septets / 140 octets / 70 UCS2 characters for singles; 153 / 134 / 67 per segment. Splitting is encoding-aware: GSM escape pairs and UTF-16 surrogate pairs are never cut, and all segments share one reference number.

const result = await client.submitSm({
  destinationAddr: "46709771337",
  shortMessage: "A long marketing blast… ".repeat(30),
});
result.segments;   // e.g. 4
result.messageIds; // one id per segment

Configure the transport method — 6-octet concat UDH (default) or SAR TLVs — via the client options:

new SmppClient({ concatenation: { method: "sar" } });        // sar_* TLVs
new SmppClient({ concatenation: { wideRef: true } });        // 16-bit UDH refs
new SmppClient({ concatenation: false });                    // send as-is (old behavior)

Buffers and messages with an explicit udh are never split — you own the framing.

Encodings

Leave dataCoding unset and the most compact encoding is detected per message — GSM 03.38 → Latin-1 → UCS2 — and stamped onto the PDU:

await client.submitSm({ destinationAddr: "...", shortMessage: "hello" });   // GSM, dataCoding 0x01
await client.submitSm({ destinationAddr: "...", shortMessage: "привет" });  // UCS2, dataCoding 0x08

Force an encoding by setting dataCoding explicitly (DATA_CODING.UCS2, …); binary payloads go through untouched as Buffers with DATA_CODING.BINARY.

Timeouts and cancellation

Every operation accepts per-request options:

const controller = new AbortController();
const pending = client.submitSm(params, {
  timeoutMs: 5_000,
  signal: controller.signal,
});
controller.abort(); // rejects with SmppAbortError

Other operations

// Payload in the message_payload TLV instead of short_message:
await client.dataSm({ destinationAddr: "...", messagePayload: "payload" });

// Message lifecycle management:
const status = await client.querySm({ messageId: "abc", sourceAddr: "1000" });
await client.replaceSm({ messageId: "abc", sourceAddr: "1000", shortMessage: "new" });
await client.cancelSm({ messageId: "abc", sourceAddr: "1000", destinationAddr: "2000" });

For anything not covered — submit_multi, broadcast commands, custom vendor PDUs — use the raw escape hatch:

const resp = await client.request({
  command: "submit_multi",
  sourceAddr: "1000",
  destAddress: [
    { destAddrTon: 1, destAddrNpi: 1, destinationAddr: "46709771337" },
    { dlName: "vip-customers" },
  ],
  shortMessage: "multi-destination message",
});

See Custom commands for vendor extensions.

On this page