Skip to main content

Python SDK for the messaging-service.co.tz SMS API v2

Project description

pynextsms 🇹🇿

Python SDK for the NEXT SMS Tanzania SMS API v2

PyPI version Python 3.8+ License: MIT Tests Coverage Code style: black


Table of Contents


Documentation

Requirements

Features

Feature Support
Send SMS to a single recipient
Broadcast same message to multiple recipients
Send different messages to different recipients
Schedule SMS (one-time)
Schedule SMS (recurring: hourly / daily / weekly / monthly)
Flash (Class-0) SMS
Auto-retry on transient 5xx errors
Typed responses — no raw dict-wrangling
Full type annotations + py.typed (mypy strict)
Environment-variable credentials (12-factor ready)
Zero dependencies beyond requests
Python 3.8 – 3.12

Installation

pip install pynextsms

Quick Start

from pynextsms import SMSClient

client = SMSClient(token="your_bearer_token", sender_id="YOURBRAND")

resp = client.sms.send("255763930052", "Hello from PyNextSMS!")
print(resp)
# SMSResponse(✅ sent, http=200, ref='a3f1c2d4')

Authentication

Generate your Bearer Token from your Next SMS API Documentation.

Option 1 — pass credentials directly (quick scripts, notebooks)

client = SMSClient(token="your_bearer_token", sender_id="YOURBRAND")

Option 2 — environment variables (recommended for production)

export PYNEXTSMS_TOKEN="your_bearer_token"
export PYNEXTSMS_SENDER_ID="YOURBRAND"
client = SMSClient()   # reads from environment automatically

Usage Guide

1. Send a Single SMS

resp = client.sms.send("255763930052", "Hello, Ronald!")

if resp.successful:
    print(f"✅ Sent! message_id={resp.message_id}, ref={resp.reference}")
else:
    print(f"❌ Failed: {resp.raw}")

2. Broadcast to Multiple Recipients

Send the same message to many people in a single API call:

resp = client.sms.send(
    to=["255763930052", "255627350020", "255622999999"],
    text="Hello everyone — you are now registered!",
    reference="campaign_june",   # optional tracking ref
)
print(f"✅ Broadcast successful: {resp.successful}")

3. Send Different Messages to Different People

from pynextsms import MessageRecipient

resp = client.sms.send_bulk(
    messages=[
        MessageRecipient(to="255763930052", text="Hello Daniel, welcome!"),
        MessageRecipient(to="255627350020", text="Hello Patricia, welcome!"),
        MessageRecipient(to="255622999999", text="Hello Precious, welcome!"),
    ],
    reference="onboarding_batch_001",
)
print(f"✅ Sent {resp.total} personalised messages")

Each MessageRecipient can also override the sender ID:

MessageRecipient(to="255763930052", text="Hi!", sender_id="CUSTOM")

4. Schedule an SMS

from datetime import date, time
from pynextsms import ScheduleOptions

opts = ScheduleOptions(
    send_date=date(2025, 6, 1),
    send_time=time(9, 0),        # 09:00, 24-hour clock
)

resp = client.sms.schedule(
    to="255763930052",
    text="Good morning! Your session starts in 1 hour.",
    options=opts,
)
print(f"✅ Scheduled: {resp.successful}")

5. Scheduled + Recurring SMS

from pynextsms import ScheduleOptions, RepeatInterval

opts = ScheduleOptions(
    send_date  = date(2025, 6, 1),
    send_time  = time(8, 0),
    repeat     = RepeatInterval.DAILY,
    start_date = date(2025, 6, 1),
    end_date   = date(2025, 6, 30),
)

resp = client.sms.schedule(
    to="255763930052",
    text="Daily reminder: drink water 💧",
    options=opts,
)

Available repeat intervals:

Value Constant
"hourly" RepeatInterval.HOURLY
"daily" RepeatInterval.DAILY
"weekly" RepeatInterval.WEEKLY
"monthly" RepeatInterval.MONTHLY

6. Flash SMS

Pass flash=True to any send or send_bulk call:

resp = client.sms.send("255712345678", "Urgent alert!", flash=True)

7. Context Manager

The client implements __enter__ / __exit__ so it can be used as a context manager — the HTTP connection pool is automatically released on exit:

with SMSClient(token="...", sender_id="BRAND") as client:
    client.sms.send("255712345678", "Hello!")
# connection pool closed here

8. Environment Variables (Production)

Variable Description
PYNEXTSMS_TOKEN Bearer token (required if not passed to constructor)
PYNEXTSMS_SENDER_ID Default sender ID
# .env file (use python-dotenv or similar)
PYNEXTSMS_TOKEN=your_bearer_token
PYNEXTSMS_SENDER_ID=YOURBRAND
from dotenv import load_dotenv
load_dotenv()

from pynextsms import SMSClient
client = SMSClient()

Response Objects

SMSResponse

Returned by sms.send() and sms.schedule().

Attribute Type Description
successful bool True when HTTP 2xx
status_code int Raw HTTP status
message_id str | None ID assigned by API
reference str | None Tracking reference
raw dict Full JSON response body
resp = client.sms.send("255763930052", "Hello!")

print(resp.successful)    # True
print(resp.message_id)    # "msg_abc123"
print(resp.to_dict())     # plain dict
print(resp.to_json())     # JSON string

BulkSMSResponse

Returned by sms.send_bulk(). Same as SMSResponse plus:

Attribute Type Description
total int Number of messages in the batch
resp = client.sms.send_bulk([...])
print(f"Accepted {resp.total} messages")

Error Handling

All exceptions inherit from PyNextSMSError:

from pynextsms import (
    PyNextSMSError,
    AuthenticationError,
    ValidationError,
    RateLimitError,
    APIError,
)

try:
    resp = client.sms.send("255712345678", "Hello!")

except AuthenticationError:
    # Bad or missing bearer token
    print("Check your PYNEXTSMS_TOKEN.")

except ValidationError as e:
    # Bad input caught *before* the HTTP call
    print(f"Input error: {e}")

except RateLimitError as e:
    # HTTP 429
    import time
    print(f"Rate limited — retrying in {e.retry_after}s")
    time.sleep(e.retry_after or 5)

except APIError as e:
    # Any other non-2xx response
    print(f"API error (HTTP {e.status_code}): {e}")

except PyNextSMSError as e:
    # Catch-all for any other SDK error
    print(f"SDK error: {e}")

Logging

PyNextSMS uses Python's standard logging under the pynextsms logger.

import logging

# Show all SDK log messages (DEBUG and above)
logging.basicConfig(level=logging.DEBUG)

# Or configure just the pynextsms logger
logger = logging.getLogger("pynextsms")
logger.setLevel(logging.INFO)
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(message)s"))
logger.addHandler(handler)

Running Locally

1. Clone the repo

git clone https://github.com/ronaldgosso/pynextsms.git
cd pynextsms

2. Create a virtual environment

python -m venv .venv
source .venv/bin/activate        # Linux / macOS
# .venv\Scripts\activate         # Windows

3. Install in editable mode with dev extras

pip install -e ".[dev]"

4. Set your credentials

export PYNEXTSMS_TOKEN="your_bearer_token"
export PYNEXTSMS_SENDER_ID="YOURBRAND"

5. Try it out

python - << 'EOF'
from pynextsms import SMSClient

with SMSClient() as client:
    resp = client.sms.send("255763930052", "Hello from local dev!")
    print(resp)
EOF

6. Run the test suite

# All tests, verbose
pytest

# With coverage report
pytest --cov=pynextsms --cov-report=term-missing

# Specific test class
pytest tests/ -v -k "TestSend"

7. Lint & type-check

ruff check pynextsms/        # linter
black --check pynextsms/     # formatter check
mypy pynextsms/              # strict type checking

Contributing

Contributions are welcome — bug reports, feature requests, documentation improvements, and pull requests all appreciated.

Workflow

  1. Fork the repository on GitHub.
  2. Clone your fork:
    git clone https://github.com/YOUR_USERNAME/pynextsms.git
    cd pynextsms
    
  3. Create a branch for your change:
    git checkout -b feat/my-new-feature
    # or
    git checkout -b fix/the-bug-description
    
  4. Install dev dependencies:
    python -m venv .venv && source .venv/bin/activate
    pip install -e ".[dev]"
    
  5. Make your changes, then make sure all of these pass:
    pytest                     # all tests pass
    ruff check pynextsms/      # no lint errors
    black pynextsms/ tests/    # code is formatted
    mypy pynextsms/            # no type errors
    
  6. Commit with a clear message:
    git commit -m "feat: add support for sending MMS"
    
  7. Push and open a Pull Request against main.

Commit message conventions

Prefix When to use
feat: New feature
fix: Bug fix
docs: Documentation change
test: Adding or updating tests
refactor: Code change with no behaviour change
chore: Tooling, CI, config

Reporting bugs

Open an issue at github.com/ronaldgosso/pynextsms/issues and include:

  • Python version (python --version)
  • pynextsms version (pip show pynextsms)
  • Minimal code that reproduces the issue
  • Full traceback

Changelog

v1.0.0 — 2025-06-01

  • Initial release
  • sms.send() — single and broadcast sends
  • sms.send_bulk() — personalised bulk sends
  • sms.schedule() — one-time and recurring scheduled SMS
  • Flash SMS support
  • Automatic retries on 5xx errors
  • Full type annotations, py.typed marker
  • Comprehensive test suite (95% coverage)

License

MIT © Ronald Gosso — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pynextsms-1.0.0.tar.gz (22.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pynextsms-1.0.0-py3-none-any.whl (16.9 kB view details)

Uploaded Python 3

File details

Details for the file pynextsms-1.0.0.tar.gz.

File metadata

  • Download URL: pynextsms-1.0.0.tar.gz
  • Upload date:
  • Size: 22.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for pynextsms-1.0.0.tar.gz
Algorithm Hash digest
SHA256 01dab0fa86a6e8fb650081640c84c47d50db3b5805d9286af123138cb76ef05d
MD5 7ec3143eda185dbb89f65f68e9530599
BLAKE2b-256 d1f86ce56d7f64c4b54730114b383a4719480d3866d6ddf2365b9433573c4d82

See more details on using hashes here.

File details

Details for the file pynextsms-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: pynextsms-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 16.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for pynextsms-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 401dafcc03cc38a9498d835ecf81689259b339f7e8b71c8b42c0e70d54319fd7
MD5 b3fbf09550b7d637874aaeb1ebb02414
BLAKE2b-256 4e647faa4c44c384a222e74297169ca90f18370a670ae9a34a954d318036ae56

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page