zing/laravel-sms
A Laravel SMS package with a clean, driver-based API for sending text messages through multiple gateways. Configure your providers, compose messages, and dispatch SMS from anywhere in your app with minimal setup and consistent syntax—ideal for OTP codes, alerts, and transactional notifications.
Architecture fit. Unchanged and now better evidenced. The package is Laravel-native: it plugs into the framework's notification subsystem as a custom channel, so SMS becomes a delivery concern rather than bespoke application code. Release 6.7.0 confirms the design is config-driven per gateway ("Add config for ctyun"), which reinforces the key architectural property we cared about: provider-specific logic lives in config and drivers, not in domain services. For a TPM the value proposition holds — reduced custom code, familiar developer experience — and the cost remains a new third-party dependency in the outbound-messaging path.
Integration feasibility. Low effort, and materially de-risked by this release. Composer install, publish config, add the channel to a notification's delivery list, implement the notifiable's SMS routing method. 6.7.0 explicitly adds support for Laravel 13 and PHP 8.5 and updates the orchestra/testbench constraint, so the compatibility matrix question is now largely answered for the current and next major versions. Two practical caveats: (1) forward-looking support for Laravel 13/PHP 8.5 is only useful to us if it still carries our current Laravel/PHP versions — verify the constraint range, not just the newest entries; (2) the release is additive config plus dev-dependency work, so it does not by itself prove queueing, retry, or delivery-receipt semantics.
Technical risk. Improved but not resolved. The dominant risk was ecosystem validation, and this release partially offsets it: an active, versioned 6.x line (6.6.0 → 6.7.0), conventional PR-based workflow, automated maintenance (license-year bot), explicit framework/PHP support declarations, and a widening gateway set. What the release does not change: adoption metrics were not refreshed in this data set, so the prior low-star/low-dependent picture should be treated as stale-but-unverified rather than disproven; the bus factor is confirmed single-maintainer (every human-authored PR is from @zingimmick); and test coverage, security-disclosure process, and actual gateway abstraction depth remain undocumented in the notes. PHPUnit 12 support is a dev-only signal — it hints at a real CI suite but is not evidence of coverage. Supply-chain exposure is unchanged: a low-adoption package handling phone numbers and message content sits in a sensitive path. The prior provenance concern about the tag date should still be closed out by verifying tags are signed/cut from the repo, though the steady release cadence makes an anomaly less likely.
Key questions.
Stack fit. Works with any Laravel application using the notification system; complements queue workers (e.g., Horizon), environment-based configuration, and secrets management for gateway credentials. The 6.7.0 config-based gateway pattern fits our environment-driven config model cleanly. It remains a thin delivery adapter, not a platform commitment — provided we treat it that way.
Migration path. If we already have a custom SMS service or direct gateway SDK calls, introduce the package behind the notification channel and keep credentials in config. Wrap it in our own small SmsSender interface or channel wrapper so the package is swappable without touching notification classes. No data migration is required. Parallel-run in staging against the existing path before cutover.
Compatibility. Pin to 6.7.0 (or the ^6.7 line) and verify Composer constraints against our exact Laravel and PHP versions — do not assume Laravel 13 support implies our version is in range. Audit transitive provider SDK dependencies. Run our application test suite plus provider sandbox tests before approving. Note that 6.7.0 is a minor, non-breaking release with no deprecations or migration steps called out, so the upgrade path from an existing 6.x pin is low-friction.
Sequencing.
Maintenance. Small surface area and MIT licensing keep maintenance light. This release raises confidence in upstream cadence — routine dependency bumps, new gateway config, framework support kept current — which reduces (but does not eliminate) the likelihood we must carry our own patches. Keep the ~0.1 FTE estimate for dependency hygiene, upstream monitoring, and compatibility checks, and keep a private fork or patched copy available. Because version support keeps advancing (PHP 8.5, Laravel 13), schedule a recurring check that our pinned version still receives fixes once we fall behind.
Support. Community issues only — no vendor SLA — and effectively a single maintainer, so escalation is internal. Operations and support teams need a runbook covering credential rotation, provider console access, and what to do when a send fails.
Scaling. Throughput is governed by the SMS gateway and our queue workers, not by this package; ensure SMS notifications are queued and rate-limited. The real scaling constraint is per-message cost and provider quotas, so instrument send volume, failure rate, and spend. Adding gateway configs (as in 6.7.0) gives us a multi-provider lever but not automatic failover — that logic is ours to build.
Failure modes. Gateway outage causes notification failure; queued retries can duplicate SMS (cost and user annoyance) without idempotency; misconfigured credentials or invalid numbers can cause silent drops; provider 429s need backoff; absent delivery receipts means no visibility into actual delivery. Design for at-least-once delivery with deduplication and alert on failure-rate spikes.
Ramp-up. Laravel developers should be productive in under a day; operations needs a short runbook and provider-console familiarity. The larger ramp-up cost is governance: approving a low-adoption dependency and establishing the wrapper and fallback that make it safely reversible — this release makes that approval easier to defend but does not remove the need for the wrapper.
How can I help you explore Laravel packages today?