Skip to main content

smpp34

crates.io docs.rs CI license

A pure-Rust implementation of the SMPP 3.4 protocol (Short Message Peer-to-Peer): a PDU codec plus an asynchronous (tokio) client and server built on a listener-trait model.

The same engine ships two ways from one source tree, one version: a Rust crate (cargo add smpp34, zero Python dependencies) and a Rust-backed Python wheel (pip install smpp34) that exposes the identical async client/server to asyncio. The whole SMPP machinery — framing, windowing, timers, codec — runs in the Rust/tokio core; Python crosses the GIL only once per message, and the extension is free-threaded ("no-GIL") ready. See Python below.

  • Client — bind to an SMSC as an ESME (transmitter, receiver or transceiver), send submit_sm / data_sm, and receive deliver_sm and session events through your own SmppClientListener.
  • Server — accept ESME binds and dispatch submit_sm, data_sm, cancel_sm, … to your SmppServerListener; push MT traffic back out with deliver_sm.
  • Codec — encode/decode every SMPP 3.4 PDU, including optional TLV parameters.

Sessions handle the SMPP timers (session_init, enquire_link, inactivity, response), sequence-number windowing, and optional TLS.

Supported PDUs

bind_transmitter · bind_receiver · bind_transceiver (+ resps) · outbind · unbind · enquire_link · submit_sm · submit_sm_multi · deliver_sm · data_sm · query_sm · cancel_sm · replace_sm · alert_notification · generic_nack, plus arbitrary TLV (optional parameter) encode/decode.

Install

cargo add smpp34

Quick start — server

Implement SmppServerListener and hand it to an SmppServer. Every trait method has a default, so you override only the PDUs you care about — typically on_bind_transceiver and on_submit_sm.

use std::sync::Arc;
use std::net::{IpAddr, Ipv4Addr};
use async_trait::async_trait;
use smpp34::{
    SmppServer, SmppServerListener, SmppConnectionInformation, SmppError,
    bind_transceiver, bind_transceiver_resp, submit_sm, submit_sm_resp,
};

struct MyEsmeHandler;

#[async_trait]
impl SmppServerListener for MyEsmeHandler {
    async fn on_bind_transceiver(
        &self, req: bind_transceiver, _c: &SmppConnectionInformation, _s: &String,
    ) -> bind_transceiver_resp {
        if req.system_id == "esme1" && req.password == "secret" {
            req.accept("MySMSC".to_string(), Some(0x34))   // 0x34 = SMPP v3.4
        } else {
            req.reject(SmppError::ESME_RINVPASWD)
        }
    }

    async fn on_submit_sm(
        &self, req: submit_sm, _c: &SmppConnectionInformation, _s: &String,
    ) -> submit_sm_resp {
        // ... route the message ...
        req.accept("message-id-1".to_string())
    }

    // Every other method has a sensible default (binds reject, on_data_sm /
    // on_cancel_sm reject, on_unbind acks, notifications no-op), so you override
    // only what you need.
}

#[tokio::main]
async fn main() {
    let listener = Arc::new(MyEsmeHandler);
    let mut server = SmppServer::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 2775, listener);
    server.start().await;          // spawns the accept loop
    tokio::signal::ctrl_c().await.unwrap();
    server.stop().await;
}

Quick start — client

Bind to an SMSC, then submit once the bind completes (the on_smsc_bound callback hands you an SMSC you can submit through).

use std::sync::Arc;
use smpp34::client::{SmppClient, BIND_TYPE};

// `listener` implements SmppClientListener; its on_smsc_bound callback hands
// you the bound `SMSC` handle to submit through.
let listener = Arc::new(MyClientHandler::new());
let mut client = SmppClient::new(
    "smsc.example.net".to_string(), 2775, /* tls = */ false,
    BIND_TYPE::TRX,
    "esme1".to_string(), "secret".to_string(), "GATEWAY".to_string(),
    /* addr_ton */ 0, /* addr_npi */ 0, /* address_range */ String::new(),
    listener.clone(),
    /* window_size */ 20,
);
client.start().await;
// inside on_smsc_bound(smsc, _): use the fluent builder (only set what you need)
//   smsc.submit_sm()
//       .source_addr("12345")
//       .destination_addr("31600000000")
//       .short_message(b"hello")
//       .send().await?;

Python

pip install smpp34 gives a Rust-backed wheel exposing the same async client/server to asyncio. The hot path stays in the Rust/tokio core; the Python layer is an event-pull bridge that crosses the GIL once per message. abi3 wheels cover CPython 3.9+, plus free-threaded ("no-GIL") builds.

pip install smpp34

Client — connect() binds and returns an Smsc; await sends and inbound events:

import asyncio, smpp34

async def main():
    client = smpp34.Client(host="smsc.example.net", port=2775,
                           system_id="esme1", password="secret", bind_type="TRX")
    smsc = await client.connect()
    resp = await smsc.submit_sm(destination_addr="31600000000",
                                source_addr="12345", short_message=b"hello")
    print(resp.message_id, resp.is_success)

    # pull inbound deliver_sm (MO / DLR) — one GIL crossing per message
    ev = await smsc.next()                       # DeliverSmEvent | Disconnected
    if isinstance(ev, smpp34.DeliverSmEvent):
        print(ev.source_addr, ev.short_message)
    await smsc.unbind()

asyncio.run(main())

Server — await next() yields an Esme when a client binds, a SubmitSmEvent per inbound message (answer with accept/reject), or Unbound:

import asyncio, smpp34

async def main():
    server = smpp34.Server(host="0.0.0.0", port=2775, system_id="MySMSC")
    await server.start()
    sessions = {}
    while True:
        ev = await server.next()
        if isinstance(ev, smpp34.Esme):
            sessions[ev.session_id] = ev          # stash the MT send handle
        elif isinstance(ev, smpp34.SubmitSmEvent):
            ev.accept(message_id="abc")           # or ev.reject(smpp34.ESME_RMSGQFUL)
            # push MT back to that ESME (here, a delivery receipt):
            await sessions[ev.session_id].deliver_sm(
                source_addr=ev.destination_addr, destination_addr=ev.source_addr,
                esm_class=0x04, short_message=b"id:abc stat:DELIVRD")

asyncio.run(main())

Codec — encode/decode PDUs without any I/O:

pdu = smpp34.SubmitSm(source_addr="12345", destination_addr="31600000000",
                      short_message=b"hello")
wire = pdu.encode()
msg = smpp34.decode(wire)        # -> typed SubmitSm / DeliverSm / RawPdu

Runnable samples: python/examples/ (and the Rust equivalents in examples/ — client.rs / server.rs). A throughput and leak harness lives in python/perf/, mirroring the Rust examples/{perf_loopback,leak_check}.rs.

Optional parameters (TLVs)

Inbound TLVs are on pdu.tlvs in wire order, with typed accessors from the TlvList trait. Outbound, the builders take them directly:

use smpp34::{Tlv, TlvTag, TlvList};

// ESME -> SMSC
smsc.submit_sm()
    .source_addr("12345")
    .destination_addr("31600000000")
    .tlv(TlvTag::MessagePayload, "a body past the 254-byte short_message limit")
    .tlv(TlvTag::UserMessageReference, 42u16.to_be_bytes())
    .tlv_raw(0x1403, [0xAA, 0xBB])          // vendor-specific tag
    .send().await?;

// SMSC -> ESME: a delivery receipt is TLVs, nothing else
esme.deliver_sm()
    .source_addr("31600000000")
    .destination_addr("12345")
    .esm_class(0x04)
    .tlvs([
        Tlv::from_c_string(TlvTag::ReceiptedMessageId, "abc"),
        Tlv::from_u8(TlvTag::MessageStateTlv, 2),   // DELIVERED
    ])
    .send().await?;

// reading, on either side
let dlr_id = request.tlvs.receipted_message_id();

For a PDU built up front (relaying a decoded one, or data_sm, whose message body only exists as the message_payload TLV) use the *_pdu send methods — the session assigns the sequence number:

let pdu = data_sm::new(0, String::new(), 1, 1, "12345".into(), 1, 1, "31600000000".into(), 0, 0, 8)
    .with_tlvs([Tlv::from_tag(TlvTag::MessagePayload, body)]);
smsc.send_data_sm_pdu(pdu).await?;

In Python, tlvs= takes a list of Tlv(tag, value) and the tag constants are on the module:

await smsc.submit_sm("31600000000", b"hi", source_addr="12345", tlvs=[
    smpp34.Tlv(smpp34.TLV_USER_MESSAGE_REFERENCE, (42).to_bytes(2, "big")),
    smpp34.Tlv(smpp34.TLV_MESSAGE_PAYLOAD, b"the real body"),
])

ev = await smsc.next()
print([(hex(t.tag), t.value) for t in ev.tlvs])

All 44 spec-defined tags are in TlvTag / smpp34.TLV_*; unknown and vendor-specific tags (0x1400-0x3FFF) pass through byte for byte.

TLS

Pass tls = true to SmppClient::new to bind over TLS. The TLS transport is rustls (via tokio-rustls, ring backend), so no system TLS library is needed to build or run.

  • TLS 1.2 and 1.3, ECDHE key exchange with AEAD ciphers only. A peer limited to RSA key exchange or CBC suites cannot be reached.
  • The server certificate is verified against the operating system's trust store (SSL_CERT_FILE / SSL_CERT_DIR are honoured), and against the address you passed, hostname or IP. It must carry a matching subjectAltName; a certificate that only names the host in its CN is rejected.
  • No client certificate (mTLS) and no per-client CA yet.

Timers & windowing

SmppServer::new / SmppClient::new use sensible default timers. Use the *_with_default_timers constructors to set session_init, enquire_link, inactivity and response timers (milliseconds) and the buffer / window size explicitly.

Performance

Measured on a 24-core AMD Ryzen AI 9 HX 370 (single box — the SMSC and ESME are co-located, so the load generator competes for cores; separate hosts scale further). Reproduce with cargo bench and perf/docker-compose.yml.

Codec — single core, criterion (cargo bench):

Operation Throughput
submit_sm decode ~6.6 M PDU/s
submit_sm encode ~12.3 M PDU/s
deliver_sm decode / encode ~6.8 M / ~12.6 M PDU/s
TLV decode / encode ~20 M / ~14 M /s

End-to-end — real TCP, full submit_sm round-trip (send → submit_sm_resp):

Load Throughput Peak RSS
1 ESME, window 64 ~180k submit_sm/s 6 MB
4 ESMEs, window 64 ~635k submit_sm/s 7 MB

The SMSC server sustains 625k+ submit_sm/s even pinned to half the cores; past a few sessions the single-box benchmark is bound by the co-located load generator, not by smpp34.

Rust vs Python (and free-threading)

Both languages drive the same Rust/tokio engine, so the protocol work — framing, windowing, timers, codec — runs at full Rust speed either way. The difference is the Python boundary: the event-pull bridge crosses the GIL once per message.

Path Throughput Notes
Rust — 4 ESMEs, window 64 ~635k submit_sm/s full multi-threaded tokio core
Python — single asyncio loop ~25k submit_sm/s one GIL crossing per message (release wheel)
Codec decode — GIL CPython ~4.5M PDU/s (flat vs threads) the GIL serialises the pyo3 call
Codec decode — free-threaded, 4 threads ~12M PDU/s no GIL → real parallelism

A few things worth knowing:

  • Build matters. A maturin develop debug build is ~3× slower; published wheels are --release. The ~25k/s figure is a release build.
  • Tune the tokio pool with SMPP34_WORKER_THREADS (default 2). On a many-core box, a large pool thrashes the GIL on every future completion and throughput drops (24 threads ≈ 17k/s vs 1 thread ≈ 28k/s); on a free-threaded build, raise it.
  • Free-threaded ("no-GIL") is correctness-clean — the full test suite passes with the GIL off (sys._is_gil_enabled() == False) — and lets CPU-bound Python work (the codec, your per-message handlers) run in parallel, as the codec row shows. Single-process async I/O is bounded by the shared tokio runtime, so scale that across processes.
  • ~25k submit_sm/s on one event loop is already well above the per-bind rate limits carriers typically impose.

Reproduce: python/perf/perf_loopback.py (COUNT=200000 SESSIONS=4 WINDOW=64), the thread-scaling demo python/perf/perf_threads.py, and the leak check python/perf/leak_check.py — all after a release build (maturin develop --release).

Profiling

A CPU flamegraph of the loopback under load (scripts/flamegraph.sh) puts ~99.98% of samples in the kernel (the socket/syscall path) — the user-space codec barely appears. smpp34 is syscall-bound, not CPU-bound: at these rates the cost is the ~600k+ read/write syscalls per second plus the runtime's wakeups, not parsing (the codec runs at millions of PDUs/sec). The remaining headroom is therefore I/O batching — coalescing writes and cutting wakeups — not faster code.

Memory

scripts/mem_leak_test.sh installs a counting global allocator and asserts live bytes stay flat (exact — unlike noisy RSS) across both codec round-trips and bind/unbind churn. RSS holds at single-digit MB while pushing millions of PDUs. (The bind/unbind check found and now guards a real session-teardown leak — see the changelog.)

SMPP 3.4 compliance

The PDU / TLV / session support matrix is in docs/COMPLIANCE.md; docs/COMPARISON.md maps smpp34 against other SMPP stacks.

MSRV

Rust 1.80.

Stability

The SMPP 3.4 codec and the client/server session handling are used in production, and the crate follows Semantic Versioning: the public Rust API is the contract. The 17-argument send_submit_sm / send_deliver_sm remain available, but the submit_sm() / deliver_sm() builders are the recommended way to send.

License

MIT © Real Time Telecom B.V.

Maintained by Real Time Telecom B.V. — carrier-grade telecom infrastructure in Rust.

Metadata

Release files for smpp34 1.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for smpp34 1.5.0
File Size Uploaded Provenance Actions
smpp34-1.5.0.tar.gz 139.5 kB With provenance Details for smpp34-1.5.0.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for smpp34 1.5.0
File Actions
smpp34-1.5.0-cp314-cp314t-win_amd64.whl CPython 3.14 CPython 3.14 free-threading Windows x86-64 Details for smpp34-1.5.0-cp314-cp314t-win_amd64.whl
smpp34-1.5.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.14 CPython 3.14 free-threading Linux glibc 2.17+ x86-64 Details for smpp34-1.5.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
smpp34-1.5.0-cp314-cp314t-macosx_11_0_arm64.whl CPython 3.14 CPython 3.14 free-threading macOS 11.0+ ARM64 Details for smpp34-1.5.0-cp314-cp314t-macosx_11_0_arm64.whl
smpp34-1.5.0-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details for smpp34-1.5.0-cp39-abi3-win_amd64.whl
smpp34-1.5.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.9 abi3 Linux glibc 2.17+ x86-64 Details for smpp34-1.5.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
smpp34-1.5.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.9 abi3 Linux glibc 2.17+ ARM64 Details for smpp34-1.5.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
smpp34-1.5.0-cp39-abi3-macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 11.0+ ARM64 Details for smpp34-1.5.0-cp39-abi3-macosx_11_0_arm64.whl
smpp34-1.5.0-cp39-abi3-macosx_10_12_x86_64.whl CPython 3.9 abi3 macOS 10.12+ x86-64 Details for smpp34-1.5.0-cp39-abi3-macosx_10_12_x86_64.whl

Total release size: 13.8 MB

Release files / smpp34-1.5.0.tar.gz

Download URL smpp34-1.5.0.tar.gz
Size 139.5 kB
Tags Source
SHA-256 checksum
How to use checksums
23bd7286f1e26f5816a8386bf5d54333adbc5bf91718e0657e3e438e309f1ea6
BLAKE2b-256 checksum
How to use checksums
baf7a70b013ce94e412eae9ad6f5fbb088f05c685674e5135aeb33ef38f4f995
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.

Transparency log

Release files / smpp34-1.5.0-cp314-cp314t-win_amd64.whl

Download URL smpp34-1.5.0-cp314-cp314t-win_amd64.whl
Size 1.5 MB
Tags CPython 3.14 CPython 3.14 free-threading Windows x86-64
SHA-256 checksum
How to use checksums
5c702f308d6181e9e467c2940b1ca8bb98519ba0cc6e1de81c63784f3ccc5abe
BLAKE2b-256 checksum
How to use checksums
0645ab3b23de9894dcd03012afcbd8a7ef60549d50c7e0228fda1d7c4ce0b162
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.

Transparency log

Release files / smpp34-1.5.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL smpp34-1.5.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 1.8 MB
Tags CPython 3.14 CPython 3.14 free-threading Linux glibc 2.17+ x86-64
SHA-256 checksum
How to use checksums
8b69ae10914ecf988d03a88f9fcd0a516412beefbcfe56a3e64e835d1909b1fe
BLAKE2b-256 checksum
How to use checksums
65b3742664f97b5b7042a70c09d843f9f5c088f099b4c84e1f732cd2aa27cda8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.

Transparency log

Release files / smpp34-1.5.0-cp314-cp314t-macosx_11_0_arm64.whl

Download URL smpp34-1.5.0-cp314-cp314t-macosx_11_0_arm64.whl
Size 1.6 MB
Tags CPython 3.14 CPython 3.14 free-threading macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
5cf2f96ca730a7a1e509712747ac17d891d75cdb04cfd685a2a0ad6619887c93
BLAKE2b-256 checksum
How to use checksums
8512c8d277a1a32e671c854e138e3bc566d90d37b4eea35068b86d1f1c111f24
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.

Transparency log

Release files / smpp34-1.5.0-cp39-abi3-win_amd64.whl

Download URL smpp34-1.5.0-cp39-abi3-win_amd64.whl
Size 1.6 MB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
cedf2b52f948a4e4c67d9c57da9d9fe24c97f0867efca606c96fe718fbef6394
BLAKE2b-256 checksum
How to use checksums
8c95a6558f11ba4a543b1d44b0a50e86e118df76b026436f65195a5fdbb9a3d5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.

Transparency log

Release files / smpp34-1.5.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL smpp34-1.5.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 1.8 MB
Tags CPython 3.9 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
abd0a7f65d2e6732fb42b2f76e5ba966252c4757f80a1eb5decbb00fe209adcc
BLAKE2b-256 checksum
How to use checksums
d7a4502538de56fc855c5b235d505c57aa6683f81cf0facc9a901256d88077d7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.

Transparency log

Release files / smpp34-1.5.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL smpp34-1.5.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 1.9 MB
Tags CPython 3.9 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
e84b35d283e25e9739df61aee5b36b2dd6a6f9a9c28dbc0e51ffbae8286aabdc
BLAKE2b-256 checksum
How to use checksums
aa26129d06236721ac0ad2bb14948a7315a2f55a3ad4212a198446676095d34e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.

Transparency log

Release files / smpp34-1.5.0-cp39-abi3-macosx_11_0_arm64.whl

Download URL smpp34-1.5.0-cp39-abi3-macosx_11_0_arm64.whl
Size 1.7 MB
Tags CPython 3.9 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
85254d0161b43780096d46028e965d0832b1326a962c33404ca9f6965926d5ef
BLAKE2b-256 checksum
How to use checksums
7614668ec342a5c0219ce6df598ce0e2530c34fb2653141e55e1b3ac0ed20753
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.

Transparency log

Release files / smpp34-1.5.0-cp39-abi3-macosx_10_12_x86_64.whl

Download URL smpp34-1.5.0-cp39-abi3-macosx_10_12_x86_64.whl
Size 1.7 MB
Tags CPython 3.9 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
317633487adbfe8efe881978289184fa13bb2dc900ac64d35d73824e23b676dd
BLAKE2b-256 checksum
How to use checksums
cae79041faacc509edf315387250990849107a132a2a1bc5ceb5a7d4d0ed96ea
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.

Transparency log

Security for smpp34 1.5.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 9 files in this release have been uploaded with provenance metadata.

Select from 9 files

Attestation for smpp34-1.5.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.5.0 This release

9 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page