PHPackages                             1naturalway/laravel-sms - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. 1naturalway/laravel-sms

ActiveLibrary

1naturalway/laravel-sms
=======================

A driver-based SMS abstraction layer for Laravel, following the MailManager pattern.

v1.0.0(1mo ago)013↑2900%MITPHPPHP ^8.4 || ^8.5CI passing

Since Mar 29Pushed 1mo agoCompare

[ Source](https://github.com/1naturalway/laravel-sms)[ Packagist](https://packagist.org/packages/1naturalway/laravel-sms)[ RSS](/packages/1naturalway-laravel-sms/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (1)Dependencies (11)Versions (2)Used By (0)

Laravel SMS
===========

[](#laravel-sms)

A driver-based SMS abstraction layer for Laravel, following the same architectural pattern as Laravel's built-in Mail system. Swap between Twilio, logging, or a null driver with a single config change.

Installation
------------

[](#installation)

```
composer require 1naturalway/laravel-sms
```

Publish the config file:

```
php artisan vendor:publish --tag=sms-config
```

Configuration
-------------

[](#configuration)

Set the driver and credentials in your `.env` file:

```
# Choose your driver: twilio, log, null
SMS_DRIVER=null

# Default "from" number (used by drivers that don't define their own)
SMS_FROM=+15551234567
```

### Twilio

[](#twilio)

```
SMS_DRIVER=twilio
TWILIO_SID=your-account-sid
TWILIO_TOKEN=your-auth-token
TWILIO_FROM=+15551234567
```

Requires the Twilio SDK:

```
composer require twilio/sdk
```

### Log

[](#log)

```
SMS_DRIVER=log
SMS_LOG_CHANNEL=stack
```

Writes every SMS to a Laravel log channel. Useful for debugging and verifying sends in staging or CI.

### Null

[](#null)

```
SMS_DRIVER=null
```

Silently discards all messages. This is the default — no accidental sends in development.

Usage
-----

[](#usage)

### Basic Send

[](#basic-send)

```
use OneNaturalWay\Sms\Facades\Sms;

$result = Sms::send('+15559876543', 'Your verification code is 123456');

if ($result->successful()) {
    // Store $result->messageId for tracking
    // Check $result->status
    // For MMS: $result->hasMedia(), $result->mediaUrls
}
```

Every `send()` call returns an `SmsResult` DTO with these properties:

PropertyTypeDescription`messageId``?string`Provider message ID (e.g., Twilio SID)`status``?string`Provider status (e.g., `queued`, `captured`, `logged`)`to``?string`Recipient number`from``?string`Sender number`body``?string`Message body`mediaCount``?int`Number of media attachments (Twilio)`mediaUrls``array`URLs of attached media (Twilio MMS)`raw``array`Full raw response from the providerUse `$result->successful()` to check if the message was accepted — returns `true` when `messageId` is present. Use `$result->hasMedia()` to check if media was attached. The null driver always returns an unsuccessful result since nothing was sent.

### Error Handling

[](#error-handling)

The Twilio driver wraps API errors into typed `SmsException` instances so you can handle specific failure modes:

```
use OneNaturalWay\Sms\Exceptions\SmsException;

try {
    $result = Sms::send('+15551234567', 'Hello!');
} catch (SmsException $e) {
    if ($e->isBlacklisted()) {
        // Number opted out / on a blacklist — stop sending to this number
    }

    if ($e->isInvalidNumber()) {
        // Bad phone number format — flag for correction
    }

    // All SmsExceptions carry context:
    // $e->errorType     — 'blacklisted', 'invalid_number', or 'provider_error'
    // $e->phoneNumber   — the "to" number that failed
    // $e->providerCode  — the raw error code from Twilio (e.g., '21610')
    // $e->getPrevious() — the original Twilio RestException
}
```

`SmsException` extends `RuntimeException`, so uncaught errors will still surface normally in your exception handler.

### With Options

[](#with-options)

```
$result = Sms::send('+15559876543', 'Hello!', [
    'from'     => '+15550001111',  // Override the default "from" number
    'mediaUrl' => 'https://example.com/image.jpg',  // Twilio MMS
]);
```

### Driver Switching

[](#driver-switching)

```
// Use a specific driver for this call
$result = Sms::driver('log')->send('+15559876543', 'This goes to the log');

// Use the default driver
$result = Sms::send('+15559876543', 'This uses the configured default');
```

### Dependency Injection

[](#dependency-injection)

```
use OneNaturalWay\Sms\SmsManager;

class NotificationService
{
    public function __construct(
        protected SmsManager $sms,
    ) {}

    public function sendWelcome(string $phone): void
    {
        $result = $this->sms->send($phone, 'Welcome to our service!');

        if ($result->successful()) {
            logger()->info('Welcome SMS queued', ['sid' => $result->messageId]);
        }
    }
}
```

Testing
-------

[](#testing)

The package ships with a `FakeSmsProvider` that captures all messages in memory, just like Laravel's `Mail::fake()`.

```
use OneNaturalWay\Sms\Facades\Sms;

public function test_sends_verification_sms(): void
{
    $fake = Sms::fake();

    // ... trigger your code that sends SMS ...

    $fake->assertSentTo('+15559876543');
    $fake->assertSentTo('+15559876543', 'verification code');
    $fake->assertSentCount(1);
}

public function test_no_sms_sent_on_invalid_input(): void
{
    $fake = Sms::fake();

    // ... trigger code that should NOT send SMS ...

    $fake->assertNothingSent();
}

public function test_sms_body_matches_pattern(): void
{
    $fake = Sms::fake();

    // ... trigger your code ...

    $fake->assertSentToWithBody('+15559876543', function (SmsResult $result) {
        return preg_match('/\d{6}/', $result->body) === 1;
    });
}
```

### Available Assertions

[](#available-assertions)

MethodDescription`assertSentTo($number, $bodyContains?)`A message was sent to this number, optionally containing text`assertNothingSent()`No messages were sent`assertSentCount($n)`Exactly N messages were sent`assertSentToWithBody($number, $callback)`A message to this number passes the callback (receives `SmsResult`)`getSent()`Returns an array of `SmsResult` objectsCustom Drivers
--------------

[](#custom-drivers)

Register a custom driver using `extend()`, typically in a service provider's `boot()` method:

```
use OneNaturalWay\Sms\Facades\Sms;
use OneNaturalWay\Sms\Contracts\SmsProvider;

Sms::extend('vonage', function ($app, $config) {
    return new VonageSmsProvider(
        apiKey: $config['api_key'],
        apiSecret: $config['api_secret'],
        from: $config['from'] ?? $app['config']['sms.from'],
    );
});
```

Add the driver config to `config/sms.php`:

```
'drivers' => [
    // ... existing drivers ...
    'vonage' => [
        'api_key'    => env('VONAGE_API_KEY'),
        'api_secret' => env('VONAGE_API_SECRET'),
        'from'       => env('VONAGE_FROM'),
    ],
],
```

Your custom provider must implement the `SmsProvider` interface:

```
use OneNaturalWay\Sms\Contracts\SmsProvider;

use OneNaturalWay\Sms\SmsResult;

class VonageSmsProvider implements SmsProvider
{
    public function send(string $to, string $body, array $options = []): SmsResult
    {
        // Your implementation — return an SmsResult with the provider's response data
    }
}
```

UAT Strategy
------------

[](#uat-strategy)

For UAT environments, we recommend **Log** driver:

- **Log** writes messages to your Laravel log files for easy inspection. Use `SMS_DRIVER=log` when you need to verify sends in CI or staging.
- **Null** (the default) ensures no SMS is sent in development or CI unless explicitly configured.

This layered approach guarantees:

1. Production uses Twilio (or your chosen carrier) via `SMS_DRIVER=twilio`
2. UAT uses logs to capture and inspect messages
3. Development and CI use `null` or `log` — zero accidental sends

License
-------

[](#license)

MIT

###  Health Score

41

—

FairBetter than 89% of packages

Maintenance90

Actively maintained with recent releases

Popularity8

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 83.3% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

46d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/17084ad54e16e273b638275e6d4c13d77fc8bde5b6bb8a698e353c96ab8c3067?d=identicon)[ajohnson6494](/maintainers/ajohnson6494)

---

Top Contributors

[![ajohnson6494](https://avatars.githubusercontent.com/u/5192820?v=4)](https://github.com/ajohnson6494 "ajohnson6494 (10 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (2 commits)")

---

Tags

laravelsmstwiliomessaging

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/1naturalway-laravel-sms/health.svg)

```
[![Health](https://phpackages.com/badges/1naturalway-laravel-sms/health.svg)](https://phpackages.com/packages/1naturalway-laravel-sms)
```

###  Alternatives

[laravel/cashier

Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services.

2.5k25.9M107](/packages/laravel-cashier)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9682.1M97](/packages/roots-acorn)[tzsk/sms

A robust and unified SMS gateway integration package for Laravel, supporting multiple providers.

320244.3k6](/packages/tzsk-sms)[api-platform/laravel

API Platform support for Laravel

59126.4k6](/packages/api-platform-laravel)[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

245.2k](/packages/aedart-athenaeum)[shaffe/laravel-mail-log-channel

A package to support logging via email in Laravel

1286.2k](/packages/shaffe-laravel-mail-log-channel)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
