Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Sms Laravel Package

linkstreet/laravel-sms

LinkStreet's Laravel SMS package provides a simple way to send text messages from Laravel applications via configurable SMS drivers. It integrates SMS sending into your app, letting you manage gateways and deliver notifications or alerts through a clean, framework-friendly API.

View on GitHub
Deep Wiki
Context7

Getting Started

v6.4.0 is a compatibility release: the only change is Laravel 12 support (^12.0 added to the illuminate constraints). There is no new API surface, so if you are already on v6.3.x under Laravel 10/11 nothing in your integration changes. If you are planning a Laravel 12 upgrade, pin rapltech/laravel-sms:^6.4 — earlier 6.x tags will fail composer update on Laravel 12 because of the framework constraint, not because of any code breakage.

Minimal setup:

composer require rapltech/laravel-sms:^6.4
php artisan vendor:publish --tag=sms-config   # check the exact tag in the package README

Then look at, in this order:

  1. config/sms.php — the driver map is the whole mental model of this package. Every entry is driver => [credentials, from, options]. Read this file before reading any docs.
  2. The package's Sms facade / manager class — it resolves drivers lazily from that map. Most "how do I…" questions are answered by the config shape, not the API.
  3. .env — the shipped config reads credentials from env keys; copy those keys into .env.example immediately so your team and CI don't diverge.

First use case: a single transactional send from Tinker to your own handset, using a real driver and a real credential, before you write a single line of application code.

// php artisan tinker
Sms::driver('twilio')->to('+15551234567')->message('hello from tinker')->send();

If that works, every subsequent problem is an application-layer problem (queueing, formatting, tenancy) rather than a package problem. Establish that baseline first.

Implementation Patterns

Wrap the facade behind your own service. The facade is convenient in Tinker and terrible in a codebase. Bind a small SmsSender interface in a service provider and let the package be an implementation detail:

final class PackageSmsSender implements SmsSender
{
    public function send(string $e164, string $body, ?string $driver = null): void
    {
        Sms::driver($driver ?? config('sms.default'))
            ->to($e164)
            ->message($body)
            ->send();
    }
}

This is the single highest-leverage decision you will make with this package: it gives you a seam for fakes in tests, a place to normalise phone numbers, and a place to add logging/metrics without touching call sites.

Implement it as a Notification channel. Almost every send in a real app is "notify a user," not "send an SMS." A custom notification channel keeps the package out of your domain code and gets you via(), toMail/toSms symmetry, and queued notifications for free:

public function via(object $notifiable): array
{
    return [SmsChannel::class];
}

public function toSms(object $notifiable): string
{
    return "Your code is {$this->code}";
}

Pair this with ShouldQueue on the notification and the package's send call never runs in a request cycle.

Per-tenant drivers via runtime config. Multi-tenant apps need per-account credentials. Do not mutate config() globally — resolve a scoped config or construct the driver explicitly, and always pass credentials through your own resolver so you can rotate them in one place:

config(['sms.drivers.twilio.sid' => $tenant->twilio_sid]);
Sms::driver('twilio')->to($phone)->message($body)->send();

If you must do this, wrap it in a try/finally that restores the original config, otherwise a long-lived Octane worker leaks tenant credentials between requests.

Failover. For anything user-facing (OTP, 2FA), define two drivers and catch the driver exception yourself. Do not assume the package retries across drivers — confirm by reading the manager before you rely on it.

Queueing. Wrap sends in a job with $tries = 3 and $backoff = [10, 60] and a failed() handler that surfaces to your alerting. SMS is a paid, non-idempotent side effect; a naive retry sends the OTP three times and bills you three times.

Testing. Fake at your seam (SmsSender), not the package's. If you prefer to fake the package, verify the exact fake method exists in the version you installed before writing assertions against it — the test helper surface is the most version-sensitive part of most SMS packages.

Laravel 12 specifics. The 12 skeleton has no app/Http/Kernel.php; middleware and exception handling live in bootstrap/app.php. If your existing integration registered anything middleware-adjacent to intercept the package's webhook or delivery-receipt route, port that registration to bootstrap/app.php during the upgrade rather than assuming it still applies.

Gotchas and Tips

The release note is the whole diff. "Support for Laravel 12" means the package's composer constraints and CI matrix changed. There is no migration guide, no deprecations, no new config keys. Treat v6.4.0 as a no-op for behaviour and verify that with your test suite rather than by reading the changelog again.

Laravel 12 requires PHP 8.2+. If your CI matrix still runs 8.1 you will get a constraint conflict that looks like a package problem but is a runtime problem.

Check laravel/framework conflicts transitively. Laravel 12 bumped several Symfony components. If you also depend on a package that pins the old ones, composer update will resolve to Laravel 11 and silently keep you on laravel-sms 6.3.1. Run composer why-not laravel/framework ^12.0 when the upgrade "doesn't take."

Phone numbers are your problem, not the package's. Normalise to E.164 at the boundary (+15551234567) before the package sees them. Providers differ wildly: some want a leading +, some want no +, some reject +1 prefixes. Store the E.164 form, format per-driver in your adapter.

Config caching will bite you. php artisan config:cache freezes config/sms.php. Any runtime config([...]) credential swap for tenancy must run after boot and must not rely on cached values being re-read. In Octane, also reset any static driver cache the manager holds between requests.

Silent accepts. Many providers return 200 with a queued message ID and then fail at the carrier. Do not treat "no exception thrown" as "delivered." Persist the message ID, and if you need delivery truth, build the receipt webhook yourself — for this package that is application code, not package code.

Keep credentials in config, sourced from env. env() called outside config/ returns null once config is cached. If you copied a snippet that calls env('SMS_KEY') directly in a service, it will work locally and fail in production — a classic and very expensive-to-debug failure mode.

Log before you send, not after. Write the recipient, driver, and body hash to your own table (or log channel) before calling send(). When a customer says "I never got the code," the package will not tell you what happened; your own record will.

Extension point worth knowing. If you need a provider the package doesn't ship, you almost never fork it — register a custom driver in the driver map and implement the package's driver contract. Check the contract signature against the installed version; that's the one interface most likely to move between majors.

Upgrade checklist for 12. Pin ^6.4, bump PHP to 8.2 in CI and in composer.json require.php, run the full suite against the new skeleton, exercise one real send per driver in staging, and only then remove the old lockfile pin. Because this release carries no behaviour change, any failure you see in that sequence is coming from Laravel 12 or from your own code — not from the SMS package.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin