Server
Overview
SmppServer — accept ESME connections, authenticate binds, deliver messages.
SmppServer from @better-smpp/server is the SMSC side of SMPP: it accepts client
connections over TCP or TLS, authenticates binds through a hook, and hands each
connection to you as a typed SmppServerSession.
import { SmppServer } from "@better-smpp/server";
import { randomUUID } from "node:crypto";
const server = new SmppServer({
systemId: "MYSMSC",
onBind: (session, pdu) => authenticate(pdu.systemId, pdu.password),
});
server.on("session", (session) => {
session.on("submit_sm", async (pdu) => {
await session.respond(pdu, { messageId: randomUUID() });
});
});
const port = await server.listen({ port: 2775 });Options
| Option | Default | Description |
|---|---|---|
onBind | accept all | Async bind authentication hook — see Authentication |
systemId | "" | system_id reported in bind responses |
interfaceVersion | — | attach scInterfaceVersion TLV to bind responses (e.g. 0x50) |
tls | off | node:tls server options (key, cert, …) |
proxyProtocol | off | accept PROXY protocol v1/v2 headers — see TLS & PROXY |
enquireLink | off | keepalive toward clients, with dead-link detection |
windowSize / windowQueueLimit | unlimited | cap outstanding server-initiated requests per session |
requestTimeoutMs | 30000 | default timeout for server-initiated requests |
registry | standard | SmppRegistry with custom commands/TLVs |
defaultEncoding / maxPduLength | "ASCII" / 16384 | codec settings |
logger / metrics | no-op | observability hooks |
Lifecycle
const port = await server.listen({ port: 2775, host: "0.0.0.0" });
server.address(); // bound AddressInfo
server.sessions; // Set<SmppServerSession> of live sessions
await server.close(); // stop listening, destroy all sessionsServer events: session (a client connected, after TLS handshake and PROXY header),
listening, error, close.
Automatic behaviors — you never handle these yourself:
- inbound
enquire_linkis answered, - unknown command ids are answered with
generic_nack(ESME_RINVCMDID), - malformed PDU bodies are nacked with the appropriate status without killing the connection,
unbindis acknowledged and the session state moves toUNBOUND,- a second bind on a bound session is rejected with
ESME_RALYBND.