lindemannrock/craft-sms-manager

SMS gateway and management for Craft CMS with multi-provider support

Installs: 42

Dependents: 3

Suggesters: 0

Security: 0

Stars: 0

Watchers: 1

Forks: 0

Open Issues: 0

Type:craft-plugin

pkg:composer/lindemannrock/craft-sms-manager

5.9.5 2026-02-23 19:22 UTC

README

Latest Version Craft CMS PHP Logging Library License

SMS gateway and management plugin for Craft CMS 5.x with multi-provider support, analytics, and delivery tracking.

License

This is a commercial plugin licensed under the Craft License. It will be available on the Craft Plugin Store soon. See LICENSE.md for details.

⚠️ Pre-Release

This plugin is in active development and not yet available on the Craft Plugin Store. Features and APIs may change before the initial public release.

Features

  • Multi-Provider Support: Extensible provider system for different SMS gateways
    • MPP-SMS: Kuwait SMS provider with Arabic and English support
    • Extensible architecture for adding custom providers
  • Sender ID Management: Configure multiple sender IDs per provider
    • Enable/disable sender IDs individually
    • Set default sender IDs per provider
    • Handle-based API access for templates
  • Multi-Language Support: Native support for Arabic (UCS-2 encoding) and English messages
  • Comprehensive Analytics:
    • Daily SMS statistics (sent, failed, pending)
    • Language breakdown (English, Arabic, other)
    • Provider and sender ID performance tracking
    • Source plugin tracking (know which plugin triggered each SMS)
    • Configurable retention period
  • Delivery Logs:
    • Full message history with status tracking
    • Provider response logging
    • Error message capture
    • Export to CSV
    • Configurable retention and auto-cleanup
  • Dashboard: Real-time overview of SMS activity and provider status
  • User Permissions: Granular access control for providers, sender IDs, analytics, logs, and settings
  • Utilities: Clear analytics and logs from Craft's utilities section
  • Logging: Structured logging via Logging Library with configurable levels

Requirements

  • Craft CMS 5.0 or greater
  • PHP 8.2 or greater
  • Logging Library 5.0 or greater (installed automatically as dependency)

Installation

Via Composer

cd /path/to/project
composer require lindemannrock/craft-sms-manager
./craft plugin/install sms-manager

Using DDEV

cd /path/to/project
ddev composer require lindemannrock/craft-sms-manager
ddev craft plugin/install sms-manager

Via Control Panel

In the Control Panel, go to Settings → Plugins and click "Install" for SMS Manager.

Configuration

Settings

Navigate to SMS Manager → Settings in the control panel to configure:

General Settings:

  • Plugin Name: Customize the display name in the control panel

Default Provider Settings:

  • Default Provider: Provider to use when none specified
  • Default Sender ID: Sender ID to use when none specified

Analytics Settings:

  • Enable Analytics: Toggle analytics tracking
  • Analytics Limit: Maximum records to retain
  • Analytics Retention: Days to keep analytics (0 = forever)
  • Auto-Trim Analytics: Automatically clean up old records

Logs Settings:

  • Enable Logs: Toggle delivery logging
  • Logs Limit: Maximum log records to retain
  • Logs Retention: Days to keep logs (0 = forever)
  • Auto-Trim Logs: Automatically clean up old records

Interface Settings:

  • Items Per Page: Number of items in list views
  • Dashboard Refresh: Auto-refresh interval in seconds

Logging Library Settings:

  • Log Level: debug, info, warning, error

Config File

Create a config/sms-manager.php file to override default settings and define providers/sender IDs:

cp vendor/lindemannrock/craft-sms-manager/src/config.php config/sms-manager.php

The config file supports multi-environment configuration with * for global settings and environment-specific overrides:

<?php

use craft\helpers\App;

return [
    // Global settings (all environments)
    '*' => [
        // Plugin Settings
        'pluginName' => 'SMS Manager',
        'logLevel' => 'error',

        // Default Provider & Sender ID (by handle)
        'defaultProviderHandle' => 'production-provider',
        'defaultSenderIdHandle' => 'main-sender',

        // Analytics Settings
        'enableAnalytics' => true,
        'analyticsLimit' => 1000,
        'analyticsRetention' => 30,
        'autoTrimAnalytics' => true,

        // Logs Settings
        'enableLogs' => true,
        'logsLimit' => 10000,
        'logsRetention' => 30,
        'autoTrimLogs' => true,

        // Interface Settings
        'itemsPerPage' => 100,
        'refreshIntervalSecs' => 30,

        // Security Settings (outbound API requests)
        // Defaults: require HTTPS, block private networks, disallow redirects, allow port 443 only
        // Leave allowedApiHosts empty to allow any public host over HTTPS
        'security' => [
            'requireHttps' => true,
            'blockPrivateNetworks' => true,
            'allowRedirects' => false,
            'allowedPorts' => [443],
            'allowedApiHosts' => [
                'api.mpp-sms.com',
            ],
        ],

        // Provider Configuration (read-only in CP)
        'providers' => [
            'production-provider' => [
                'name' => 'Production MPP-SMS',
                'type' => 'mpp-sms',
                'enabled' => true,
                'settings' => [
                    'apiUrl' => App::env('MPP_SMS_API_URL'),
                    'apiKey' => App::env('MPP_SMS_API_KEY'),
                    'allowedCountries' => ['*'], // ['*'] for all, or ['KW', 'SA', 'AE'] for specific
                    // Optional per-provider API host allowlist
                    // 'allowedApiHosts' => ['api.mpp-sms.com'],
                ],
            ],
        ],

        // Sender ID Configuration (read-only in CP)
        'senderIds' => [
            'main-sender' => [
                'name' => 'Main Sender',
                'provider' => 'production-provider', // Reference by handle
                'senderId' => 'MYCOMPANY',
                'enabled' => true,
                'isDev' => false,
            ],
        ],
    ],

    // Development environment
    'dev' => [
        'logLevel' => 'debug',
        'defaultProviderHandle' => 'test-provider',
        'defaultSenderIdHandle' => 'test-sender',
    ],

    // Production environment
    'production' => [
        'logLevel' => 'error',
    ],
];

Config File Behavior:

  • Settings defined in the config file are read-only in the Control Panel
  • Providers and sender IDs from config are displayed with a "Config" badge
  • Config items cannot be edited or deleted via CP (only through the config file)
  • Config items take precedence over database items with the same handle
  • A warning is shown in CP when defaults are set via config file

Security Settings

SMS Manager applies a safe outbound request policy for provider API calls:

  • HTTPS required by default
  • Private/loopback/link-local networks are blocked
  • Redirects are disabled by default
  • Only port 443 is allowed by default

You can optionally allow specific API hosts globally or per provider:

  • security.allowedApiHosts (global)
  • providers.*.settings.allowedApiHosts (per provider)

If allowedApiHosts is empty, any public HTTPS host is allowed.

Usage

Setting Up a Provider

  1. Navigate to SMS Manager → Providers
  2. Click New Provider
  3. Select provider type (e.g., MPP-SMS)
  4. Enter provider settings:
    • Name: Display name for the provider
    • API Key: Your provider API key (supports environment variables: $MPP_SMS_API_KEY)
    • API URL: Optional custom endpoint (defaults to provider's standard URL)
  5. Enable the provider and save

Setting Up Sender IDs

  1. Navigate to SMS Manager → Sender IDs
  2. Click New Sender ID
  3. Configure:
    • Name: Display name (e.g., "My Brand")
    • Handle: Unique identifier for templates (e.g., my-brand)
    • Sender ID: The actual sender ID registered with your provider
    • Provider: Select which provider this sender ID belongs to
    • Default: Set as default for this provider
  4. Enable and save

Sending SMS from PHP

use lindemannrock\smsmanager\SmsManager;

// Basic send (uses default provider and sender ID)
$success = SmsManager::$plugin->sms->send(
    '+96512345678',           // Recipient
    'Hello from Craft CMS!',  // Message
    'en'                      // Language: 'en' or 'ar'
);

// Send with specific provider and sender ID
$success = SmsManager::$plugin->sms->send(
    '+96512345678',
    'مرحبا من كرافت!',        // Arabic message
    'ar',                     // Arabic language
    $providerId,              // Provider ID
    $senderIdId,              // Sender ID
    'my-plugin',              // Source plugin (for analytics)
    $elementId                // Source element ID (optional)
);

// Send using sender ID handle
$success = SmsManager::$plugin->sms->sendWithHandle(
    '+96512345678',
    'Hello!',
    'my-brand',               // Sender ID handle
    'en',
    'my-plugin'
);

// Send with detailed response
$result = SmsManager::$plugin->sms->sendWithDetails(
    '+96512345678',
    'Hello!',
    'en',
    $providerId,
    $senderIdId
);

// Result includes:
// - success: bool
// - messageId: string|null
// - response: string|null (raw provider response)
// - error: string|null
// - executionTime: int (milliseconds)
// - providerName: string|null
// - senderIdName: string|null
// - senderIdValue: string|null
// - recipient: string

Sending SMS from Twig

{# Send SMS using the Twig variable #}
{% set result = craft.smsHelper.send('+96512345678', 'Hello!', 'en') %}

{% if result %}
    <p>SMS sent successfully!</p>
{% else %}
    <p>Failed to send SMS.</p>
{% endif %}

{# Send with specific sender ID handle #}
{% set result = craft.smsHelper.sendWithHandle('+96512345678', 'Hello!', 'my-brand', 'en') %}

{# Get all enabled sender IDs #}
{% set senderIds = craft.smsHelper.getSenderIds() %}
{% for senderId in senderIds %}
    <option value="{{ senderId.id }}">{{ senderId.name }}</option>
{% endfor %}

{# Get sender IDs for a specific provider #}
{% set senderIds = craft.smsHelper.getSenderIds(providerId) %}

Integration with Other Plugins

SMS Manager tracks which plugin triggered each SMS for analytics:

// In your custom plugin
SmsManager::$plugin->sms->send(
    $phoneNumber,
    $message,
    'en',
    null,                    // Use default provider
    null,                    // Use default sender ID
    'my-custom-plugin',      // Your plugin handle
    $entry->id               // Optional: related element ID
);

This appears in analytics and logs, allowing you to see SMS usage by source plugin.

Providers

MPP-SMS

Kuwait SMS provider with support for Arabic and English messages.

Settings:

  • API Key: Your MPP-SMS API key (required)
  • API URL: Custom endpoint (optional, defaults to https://api.mpp-sms.com/api/send.aspx)

Features:

  • Automatic UCS-2 encoding for Arabic messages
  • English URL encoding
  • Message ID extraction from responses
  • Full error logging

Environment Variables:

# .env
MPP_SMS_API_KEY=your-api-key-here
// In provider settings, use:
$MPP_SMS_API_KEY

Creating Custom Providers

Extend BaseProvider to create custom SMS providers:

<?php
namespace mymodule\providers;

use lindemannrock\smsmanager\providers\BaseProvider;
use lindemannrock\smsmanager\records\ProviderRecord;

class MyProvider extends BaseProvider
{
    public static function handle(): string
    {
        return 'my-provider';
    }

    public static function displayName(): string
    {
        return 'My SMS Provider';
    }

    public static function description(): string
    {
        return 'Description of my provider.';
    }

    public static function supportsConnectionTest(): bool
    {
        return true; // If you implement testConnection()
    }

    public function getSettingsHtml(?ProviderRecord $provider = null): string
    {
        return $this->renderSettingsTemplate('my-module/provider-settings', [
            'provider' => $provider,
        ]);
    }

    public function validateSettings(array $settings): array
    {
        $errors = [];
        if (empty($settings['apiKey'])) {
            $errors['apiKey'] = 'API Key is required.';
        }
        return $errors;
    }

    public function send(string $to, string $message, string $senderId, string $language, array $settings): array
    {
        // Implement your provider's API call
        return [
            'success' => true,
            'messageId' => 'msg-123',
            'response' => 'OK',
            'error' => null,
        ];
    }
}

Register your provider in your module's init():

use lindemannrock\smsmanager\services\ProvidersService;
use lindemannrock\smsmanager\events\RegisterProvidersEvent;
use yii\base\Event;

Event::on(
    ProvidersService::class,
    ProvidersService::EVENT_REGISTER_PROVIDERS,
    function(RegisterProvidersEvent $event) {
        $event->providers[] = MyProvider::class;
    }
);

Analytics

Viewing Analytics

Navigate to SMS Manager → Analytics to see:

  • Total messages sent vs failed
  • Daily trends chart
  • Language breakdown (English, Arabic, other)
  • Provider performance comparison
  • Source plugin breakdown

Analytics API

use lindemannrock\smsmanager\SmsManager;

// Get analytics service
$analytics = SmsManager::$plugin->analytics;

// Get summary statistics
$summary = $analytics->getSummary();
// Returns: totalSent, totalFailed, totalPending, successRate

// Get daily statistics
$daily = $analytics->getDailyStats($startDate, $endDate);

// Get provider breakdown
$byProvider = $analytics->getByProvider();

// Get language breakdown
$byLanguage = $analytics->getByLanguage();

SMS Logs

Viewing Logs

Navigate to SMS Manager → SMS Logs to see:

  • All sent messages with status (sent, failed, pending)
  • Recipient, message content, language
  • Provider and sender ID used
  • Provider response and error messages
  • Source plugin and element tracking

Log Statuses

  • Pending: Message queued, not yet sent
  • Sent: Successfully delivered to provider
  • Failed: Provider returned an error

Exporting Logs

Click Export to download logs as CSV with columns:

  • Date, Recipient, Message, Language
  • Provider, Sender ID, Status
  • Error Message, Provider Message ID
  • Source Plugin, Source Element ID

Utilities

Access via Utilities → SMS Manager:

Analytics & Logs

  • Clear All Analytics: Remove all analytics data
  • Clear All SMS Logs: Remove all delivery logs

Both actions require confirmation and respect user permissions.

Permissions

Provider Permissions

  • Manage providers
    • View providers
    • Create providers
    • Edit providers
    • Delete providers

Sender ID Permissions

  • Manage sender IDs
    • View sender IDs
    • Create sender IDs
    • Edit sender IDs
    • Delete sender IDs

Analytics Permissions

  • View analytics
    • Export analytics
    • Clear analytics

Log Permissions

  • View logs
    • Download logs

Settings Permissions

  • Manage settings

Logging

SMS Manager uses the LindemannRock Logging Library for system logging.

Log Levels

  • Error: Critical errors only (default)
  • Warning: Errors and warnings
  • Info: General information
  • Debug: Detailed debugging (requires devMode)

Configuration

// config/sms-manager.php
return [
    'logLevel' => 'error', // error, warning, info, or debug
];

Note: Debug level requires Craft's devMode to be enabled.

Log Files

  • Location: storage/logs/sms-manager-YYYY-MM-DD.log
  • Retention: 30 days (automatic cleanup)
  • Web Interface: View logs at SMS Manager → System Logs

Events

use lindemannrock\smsmanager\services\SmsService;
use lindemannrock\smsmanager\events\SendEvent;
use yii\base\Event;

// Before sending SMS
Event::on(
    SmsService::class,
    SmsService::EVENT_BEFORE_SEND,
    function(SendEvent $event) {
        // Access: $event->to, $event->message, $event->language
        // Set $event->isValid = false to cancel
    }
);

// After sending SMS
Event::on(
    SmsService::class,
    SmsService::EVENT_AFTER_SEND,
    function(SendEvent $event) {
        // Access: $event->success, $event->messageId, $event->response
    }
);

// Register custom providers
use lindemannrock\smsmanager\services\ProvidersService;
use lindemannrock\smsmanager\events\RegisterProvidersEvent;

Event::on(
    ProvidersService::class,
    ProvidersService::EVENT_REGISTER_PROVIDERS,
    function(RegisterProvidersEvent $event) {
        $event->providers[] = MyCustomProvider::class;
    }
);

Troubleshooting

SMS Not Sending

  1. Check provider is enabled: SMS Manager → Providers → ensure status is enabled
  2. Check sender ID is enabled: SMS Manager → Sender IDs → ensure status is enabled
  3. Verify API credentials: Check API key is correct in provider settings
  4. Check logs: SMS Manager → SMS Logs for error messages
  5. Check system logs: SMS Manager → System Logs for detailed errors

Arabic Messages Not Displaying Correctly

  • Ensure language is set to 'ar' when sending
  • MPP-SMS automatically uses UCS-2 encoding for Arabic
  • Check recipient device supports Arabic SMS

Analytics Not Tracking

  • Verify analytics is enabled in settings
  • Check enableAnalytics setting is true
  • Analytics only tracks when messages are sent via the service

Provider Response Errors

Common MPP-SMS errors:

  • Invalid API Key: Check your API key in provider settings
  • Invalid Sender ID: Sender ID not registered with provider
  • Invalid Mobile Number: Check phone number format
  • Insufficient Balance: Top up your provider account

Support

License

This plugin is licensed under the Craft License. See LICENSE.md for details.

Developed by LindemannRock