better-smpp
Server

Sessions

Typed request events and SMSC-side operations on SmppServerSession.

Every accepted connection is an SmppServerSession, delivered via the server's session event. It emits a typed event per inbound request command and exposes the SMSC-side operations.

Handling requests

server.on("session", (session) => {
  session.on("submit_sm", async (pdu) => {
    const id = await enqueue(pdu);
    await session.respond(pdu, { messageId: id });
  });

  session.on("query_sm", async (pdu) => {
    const state = await lookup(pdu.messageId);
    await session.respond(pdu, { messageId: pdu.messageId, messageState: state });
  });

  session.on("data_sm", async (pdu) => { /* … */ });
});

respond(pdu, fields?) builds the matching _resp with the request's sequence number. Reject with a status instead of fields:

await session.respond(pdu, { commandStatus: CommandStatus.ESME_RINVDSTADR });

Available request events: submit_sm, data_sm, submit_multi, query_sm, cancel_sm, replace_sm, broadcast_sm, query_broadcast_sm, cancel_broadcast_sm, plus lifecycle events bound, unbound, stateChange, pdu, unknownPdu, error, close. (enquire_link and unbind are handled for you.)

Reassembling multipart submissions

Clients may split long messages across several submit_sm PDUs. Use the core reassembler:

import { MessageReassembler } from "@better-smpp/core";

server.on("session", (session) => {
  const reassembler = new MessageReassembler();
  session.on("submit_sm", async (pdu) => {
    await session.respond(pdu, { messageId: nextId() });
    const message = reassembler.add(pdu);
    if (message) {
      // message.message is the complete text across all segments
      await route(message);
    }
  });
});

Delivering to the client

Sessions bound as receiver or transceiver can be pushed messages and receipts:

// Mobile-originated message:
await session.deliverSm({
  sourceAddr: "46709771337",
  destinationAddr: session.systemId!,
  shortMessage: "hello from a handset",
});

// Delivery receipt:
await session.deliverSm({
  sourceAddr: destination,
  destinationAddr: source,
  esmClass: 0x04,
  receiptedMessageId: id,
  messageState: 2,
  shortMessage: `id:${id} sub:001 dlvrd:001 stat:DELIVRD err:000 text:`,
});

deliverSm resolves with the client's deliver_sm_resp (and rejects with SmppCommandError if the client refuses). Also available: dataSm, alertNotification, outbind, and the raw escape hatches session.request(pdu) / session.send(pdu) for custom commands.

Configure windowSize on the server to bound in-flight deliveries per session, and enquireLink to detect dead clients.

Session context

session.systemId;      // bound system_id
session.mode;          // "transmitter" | "receiver" | "transceiver"
session.sessionState;  // SessionState (server's perspective)
session.remoteAddress; // client IP — PROXY protocol source when present
session.remotePort;
session.proxyAddress;  // the load balancer, when PROXY protocol was used
session.secure;        // TLS?
session.connection;    // the underlying SmppConnection (advanced)

Teardown: session.close() (graceful) or session.destroy(). Closed sessions leave server.sessions automatically.

On this page