Python SDK for the messaging-service.co.tz SMS API v2
Project description
Table of Contents
- Documentation
- Requirements
- Features
- Installation
- Quick Start
- Authentication
- Usage Guide
- Response Objects
- Error Handling
- Logging
- Running Locally
- Contributing
- Changelog
- License
Documentation
Requirements
- Next SMS Registration
- Python 3.8+
- requests >= 2.28
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
- Fork the repository on GitHub.
- Clone your fork:
git clone https://github.com/YOUR_USERNAME/pynextsms.git cd pynextsms
- Create a branch for your change:
git checkout -b feat/my-new-feature # or git checkout -b fix/the-bug-description
- Install dev dependencies:
python -m venv .venv && source .venv/bin/activate pip install -e ".[dev]"
- 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
- Commit with a clear message:
git commit -m "feat: add support for sending MMS"
- 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 sendssms.send_bulk()— personalised bulk sendssms.schedule()— one-time and recurring scheduled SMS- Flash SMS support
- Automatic retries on 5xx errors
- Full type annotations,
py.typedmarker - Comprehensive test suite (95% coverage)
License
MIT © Ronald Gosso — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
01dab0fa86a6e8fb650081640c84c47d50db3b5805d9286af123138cb76ef05d
|
|
| MD5 |
7ec3143eda185dbb89f65f68e9530599
|
|
| BLAKE2b-256 |
d1f86ce56d7f64c4b54730114b383a4719480d3866d6ddf2365b9433573c4d82
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
401dafcc03cc38a9498d835ecf81689259b339f7e8b71c8b42c0e70d54319fd7
|
|
| MD5 |
b3fbf09550b7d637874aaeb1ebb02414
|
|
| BLAKE2b-256 |
4e647faa4c44c384a222e74297169ca90f18370a670ae9a34a954d318036ae56
|