ghanem / laravel-smsmisr
Send SMS and SMS Notification via SMS Misr for Laravel
Requires
- php: ^8.1
- illuminate/http: ^10.0|^11.0|^12.0
- illuminate/notifications: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0|^10.0
- phpunit/phpunit: ^10.0|^11.0
README
Laravel package to send SMS and SMS notifications via SMS Misr from your Laravel application.
Requirements
- PHP >= 8.1
- Laravel 10, 11, or 12
- SMS Misr account (username/password or API token)
Installation
composer require ghanem/laravel-smsmisr
The package uses Laravel's auto-discovery, so the service provider and facade are registered automatically.
Publish the configuration file:
php artisan vendor:publish --provider="Ghanem\LaravelSmsmisr\SmsmisrServiceProvider" --tag="smsmisr-config"
Add your credentials to .env:
SMSMISR_USERNAME=my_username SMSMISR_PASSWORD=my_password SMSMISR_SENDER=my_sender SMSMISR_ENVIRONMENT=1
Or use token-based authentication:
SMSMISR_TOKEN=my_api_token SMSMISR_SENDER=my_sender SMSMISR_ENVIRONMENT=1
Usage
Sending SMS
use Ghanem\LaravelSmsmisr\Facades\Smsmisr; $response = Smsmisr::send('Hello world', '01012345678'); if ($response->isSuccessful()) { echo $response->message; }
Using the service container:
$response = app('smsmisr')->send('Hello world', '01012345678');
Bulk SMS
Send to multiple recipients (up to 500K numbers per request):
$response = Smsmisr::sendBulk('Hello everyone', [ '01012345678', '01112345678', '01212345678', ]);
OTP / Verification SMS
$response = Smsmisr::sendVerify('1234', '01012345678', null, 'your-template');
Scheduled SMS
$response = Smsmisr::send( message: 'Happy Birthday!', to: '01012345678', scheduledAt: new DateTime('2026-04-01 09:00:00'), ); // Also works with bulk $response = Smsmisr::sendBulk( message: 'Sale starts now!', recipients: ['01012345678', '01112345678'], scheduledAt: new DateTime('2026-04-01 09:00:00'), );
Queue (Async Sending)
Send SMS in the background via Laravel queues:
use Ghanem\LaravelSmsmisr\Facades\Smsmisr; // Queue a single SMS Smsmisr::queue('Hello', '01012345678'); // Queue bulk SMS Smsmisr::queueBulk('Hello everyone', ['01012345678', '01112345678']); // Queue verification SMS Smsmisr::queueVerify('1234', '01012345678', null, 'your-template');
Configure the queue name in .env:
SMSMISR_QUEUE=sms
Or dispatch the jobs directly:
use Ghanem\LaravelSmsmisr\Jobs\SendSmsJob; use Ghanem\LaravelSmsmisr\Jobs\SendBulkSmsJob; use Ghanem\LaravelSmsmisr\Jobs\SendVerifySmsJob; SendSmsJob::dispatch('Hello', '01012345678'); SendBulkSmsJob::dispatch('Hello', ['01012345678', '01112345678']); SendVerifySmsJob::dispatch('1234', '01012345678', null, 'template');
Checking Balance
$response = Smsmisr::balance(); echo $response->raw['balance']; $response = Smsmisr::balanceVerify();
Health Check
if (Smsmisr::health()) { // API is reachable and credentials are valid }
Response Object
All API methods return a SmsmisrResponse object:
$response->isSuccessful(); // bool $response->isFailed(); // bool $response->code; // int (e.g. 1901) $response->message; // string $response->raw; // array (full API response) $response->toArray(); // array
Error Handling
use Ghanem\LaravelSmsmisr\Exceptions\SmsmisrApiException; use Ghanem\LaravelSmsmisr\Exceptions\SmsmisrAuthenticationException; use Ghanem\LaravelSmsmisr\Exceptions\SmsmisrInsufficientBalanceException; use Ghanem\LaravelSmsmisr\Exceptions\SmsmisrRateLimitException; try { $response = Smsmisr::send('Hello', '01012345678'); } catch (SmsmisrAuthenticationException $e) { // Invalid credentials } catch (SmsmisrInsufficientBalanceException $e) { // Not enough SMS credits } catch (SmsmisrRateLimitException $e) { // Rate limit exceeded } catch (SmsmisrApiException $e) { $e->getCode(); // Error code $e->getMessage(); // Error message $e->getResponse(); // Full response array }
Phone Number Normalization
The package automatically normalizes Egyptian phone numbers to international format:
01012345678->201012345678+201012345678->20101234567800201012345678->201012345678010-1234-5678->201012345678
Disable in config:
SMSMISR_AUTO_NORMALIZE=false
Validation Rule
use Ghanem\LaravelSmsmisr\Rules\EgyptianPhoneNumber; $request->validate([ 'phone' => ['required', new EgyptianPhoneNumber], ]);
Validates prefixes: 010, 011, 012, 015.
Events
| Event | When | Properties |
|---|---|---|
SmsSending |
Before sending | to, message, sender, type |
SmsSent |
After success | to, message, sender, response, type |
SmsFailed |
On failure | to, message, sender, exception, type |
LowBalance |
Balance check alert | smsBalance, verifyBalance, threshold |
The type is 'sms', 'otp', or 'bulk'.
use Ghanem\LaravelSmsmisr\Events\SmsSent; use Ghanem\LaravelSmsmisr\Events\LowBalance; Event::listen(SmsSent::class, function (SmsSent $event) { logger("SMS sent to {$event->to}"); }); Event::listen(LowBalance::class, function (LowBalance $event) { // Send alert to admin });
Artisan Commands
# Display current SMS and Verify balance php artisan smsmisr:balance # Check balance against threshold and dispatch LowBalance event if below php artisan smsmisr:check-balance php artisan smsmisr:check-balance --threshold=500
Schedule the balance check in your routes/console.php:
Schedule::command('smsmisr:check-balance')->daily();
Notifications
namespace App\Notifications; use Ghanem\LaravelSmsmisr\SmsmisrChannel; use Ghanem\LaravelSmsmisr\SmsmisrMessage; use Illuminate\Notifications\Notification; class OrderShipped extends Notification { public function via($notifiable): array { return [SmsmisrChannel::class]; } public function toSmsmisr($notifiable): SmsmisrMessage { return (new SmsmisrMessage('Your order has been shipped!', $notifiable->phone)) ->sender('MyApp'); } }
OTP Notification
public function toSmsmisr($notifiable): SmsmisrMessage { return (new SmsmisrMessage()) ->to($notifiable->phone) ->asVerification('1234', 'your-template-id'); }
Scheduled Notification
public function toSmsmisr($notifiable): SmsmisrMessage { return (new SmsmisrMessage('Reminder: appointment tomorrow', $notifiable->phone)) ->scheduledAt(new DateTime('2026-04-01 09:00:00')); }
SmsmisrMessage API
(new SmsmisrMessage(string $message, string $to)) ->message(string $message) ->to(string $to) ->sender(string $sender) ->unicode(bool $unicode) ->asVerification(string $code, ?string $template) ->scheduledAt(DateTimeInterface $dateTime)
Testing
In Your Application
use Ghanem\LaravelSmsmisr\Facades\Smsmisr; public function test_order_sends_sms(): void { Smsmisr::fake(); // ... trigger SMS ... Smsmisr::assertSent('01012345678', 'Your order has been shipped!'); Smsmisr::assertSentCount(1); }
Available assertions:
Smsmisr::fake(); // Sent Smsmisr::assertSent($to, $message); Smsmisr::assertSentCount($count); Smsmisr::assertNothingSent(); Smsmisr::assertSentWithSchedule($to); // Verification Smsmisr::assertVerifySent($to, $code); Smsmisr::assertVerifySentCount($count); // Bulk Smsmisr::assertBulkSent($message); Smsmisr::assertBulkSentCount($count); Smsmisr::assertBulkSentTo($recipients); // Queue Smsmisr::assertQueued($to, $message); Smsmisr::assertQueuedCount($count); Smsmisr::assertVerifyQueued($to, $code); Smsmisr::assertNothingQueued(); // Inspect Smsmisr::getSent(); Smsmisr::getBulk(); Smsmisr::getVerified(); Smsmisr::getQueued();
Running Package Tests
composer test
Configuration
| Key | Env Variable | Default | Description |
|---|---|---|---|
environment |
SMSMISR_ENVIRONMENT |
1 |
1 = Live, 2 = Test |
endpoint |
SMSMISR_ENDPOINT |
https://smsmisr.com/api/ |
API endpoint |
username |
SMSMISR_USERNAME |
null |
Account username |
password |
SMSMISR_PASSWORD |
null |
Account password |
token |
SMSMISR_TOKEN |
null |
API token (alternative auth) |
sender |
SMSMISR_SENDER |
null |
Default sender name |
auto_normalize |
SMSMISR_AUTO_NORMALIZE |
true |
Auto-normalize phone numbers |
timeout |
SMSMISR_TIMEOUT |
30 |
HTTP timeout (seconds) |
retries |
SMSMISR_RETRIES |
0 |
Retry attempts on failure |
retry_delay |
SMSMISR_RETRY_DELAY |
100 |
Delay between retries (ms) |
rate_limit |
SMSMISR_RATE_LIMIT |
null |
Max messages per minute |
queue |
SMSMISR_QUEUE |
null |
Queue name for async sending |
log_channel |
SMSMISR_LOG_CHANNEL |
null |
Log channel for SMS operations |
low_balance_threshold |
SMSMISR_LOW_BALANCE_THRESHOLD |
100 |
Alert threshold for balance check |
License
MIT