Blog

How to send SMS text messages with PHP

Amy Elliott Amy Elliott
· 8 min read · Tips and resources · March 24th, 2026
You can use PHP to quickly and easily start sending bulk SMS messages to your customers in minutes. Here’s how to add SMS sending to your stack.

Transactional SMS notifications are a great way for businesses to reach customers. It’s quick, it’s reliable, and in fact, SMS has a 98%+ open rate, much higher than that of email.

The good news is, you can use good old PHP combined with an advanced REST API and SMS gateway to effortlessly implement SMS sending.

In this tutorial, we’ll go through how to send SMS messages (with PHP code examples) and the best practices for sending transactional SMS.

Prerequisites

Combining MailerSend’s SMS API and the PHP SDK is a quick and easy way to start sending bulk SMS. But there are a few things you’ll need to have ready before you can start sending.

  • Account with an SMS provider: MailerSend’s Starter and Professional plans include SMS, which you can test for free with a trial phone number. Note: MailerSend’s SMS feature is currently available for the US and Canada.

  • Verified phone number: For testing, you can use your Trial number. To get started with your own number, you’ll need to purchase a number and verify it. To purchase a phone number:

    1. Go to Plan and billing.

    2. Select the Phone number add-on.

    3. Choose a phone number and click Add to cart.

    4. Complete the purchase and verify your phone number.

      For more information, read How to purchase a phone number.

  • API token with SMS permissions: To create a new API key in MailerSend, go to Integrations > API tokens - Manage > Create new token

  • PHP environment with API installed: PHP 7.4, PSR-7 and PSR-18 based HTTP adapter. To install the correct implementations for PSR-7 and PSR-18:

composer require php-http/guzzle7-adapter nyholm/psr7

And to install MailerSend:

composer require mailersend/mailersend

How to send text messages with PHP (using the MailerSend SMS API)

1. Create a PHP project named SendSms.php and configure your authentication credentials by adding your API key as an environment variable named MAILERSEND_API_KEY.

2. If you haven’t already, install the MailerSend PHP SDK:

composer require mailersend/mailersend

3. To start sending SMS, save the following code to your PHP file. Remember to load your API key with getenv().

<?php

require __DIR__ . "/../vendor/autoload.php";

use MailerSend\MailerSend;
use MailerSend\Helpers\Builder\SmsParams;

$mailersend = new MailerSend([
    "api_key" => getenv("MAILERSEND_API_KEY"),
]);

$smsParams = (new SmsParams())
    ->setFrom("+12065550101")
    ->setTo(["+12065550102", "+12065550103"])
    ->setText("This text message is a test.");

$sms = $mailersend->sms->send($smsParams);

Run the code and your SMS will be sent!

Request parameters

Required:

  • from: The number being used to send the message (your account phone number) in E164 format

  • to: The numbers(s) the message is being sent to in E164 format

  • text: The contents of the SMS message

Optional:

  • personalization: Personalization of the message through the use of {{var}} variables

Learn more about request parameters in our API docs.

How to check the status of your message

You can check the status of any text message you have sent via 2 methods: through the API or in the app.

To check the status via API, use the following code, replacing sms_message_id with the actual message ID:

<?php

require __DIR__ . '/../vendor/autoload.php';

use MailerSend\MailerSend;

$mailersend = new MailerSend([
    'api_key' => getenv('MAILERSEND_API_KEY')
]);

$smsMessage = $mailersend->smsMessage->find('sms_message_id');

Your message will either be processed, queued, sent, delivered, or failed. The response will look something like this:

{
	"data": {
		"id": "01h909rj94ybjnvpke60w866n6",
		"from": "+18332647501",
		"to": [
			"+16203221059"
		],
		"text": "This text message is a test.",
		"paused": false,
		"created_at": "2023-08-29T09:24:58.000000Z",
		"sms": [
			{
				"id": "01h909rjj42mjxcpkxv6asq1jn",
				"from": "+18332647501",
				"to": "+16203221059",
				"text": "This text message is a test.",
				"compiled_text": "This text message is a test.",
				"status": "sent",
				"segment_count": 1,
				"error_type": null,
				"error_description": null,
				"created_at": "2023-08-29T09:24:59.000000Z"
			}
		],
		"sms_activity": [
			{
				"from": "+18332647501",
				"to": "+16203221059",
				"created_at": "2023-08-29T09:24:59.000000Z",
				"status": "processed",
				"sms_message_id": "01h909rj94ybjnvpke60w866n6"
			},
			{
				"from": "+18332647501",
				"to": "+16203221059",
				"created_at": "2023-08-29T09:24:59.000000Z",
				"status": "queued",
				"sms_message_id": "01h909rj94ybjnvpke60w866n6"
			},
			{
				"from": "+18332647501",
				"to": "+16203221059",
				"created_at": "2023-08-29T09:24:59.000000Z",
				"status": "sent",
				"sms_message_id": "01h909rj94ybjnvpke60w866n6"
			}
		]
	}
}

To check the status in the MailerSend app, simply navigate to SMS and Activity.

A view of the SMS activity page in MailerSend.

Tracking delivery with webhooks

You can optimize SMS delivery tracking with webhooks to listen for sent, delivered and failed events, allowing you to send a callback with a payload about the text message that was sent. This provides the most recent information and data on message activity without requiring constant API polling.

When a webhook is fired for a particular event, you can trigger a workflow (for example, if an SMS fails, use a fallback mechanism such as sending the message through an alternative channel) or set up real-time notifications to monitor for potential issues. 

The available webhook events in MailerSend are sms.sent, sms.delivered and sms.failed.

How to use personalization in text messages

You can add variables to your text messages using the personalization parameter. Personalization variables can be added to the text fields using {{ var }} syntax. Here is the sample code to send an SMS with a personalization variable.

<?php

require __DIR__ . "/../vendor/autoload.php";

use MailerSend\MailerSend;
use MailerSend\Helpers\Builder\SmsParams;

$mailersend = new MailerSend([
    "api_key" => getenv("MAILERSEND_API_KEY"),
]);

$smsParams = (new SmsParams())
    ->setFrom("+12065550101")
    ->setTo(["+12065550102"])
    ->setText("Text {{ var }}")
    ->setPersonalization([
        new SmsPersonalization("+12065550102", [
            "var" => "variable",
            "number" => 123,
            "object" => [
                "key" => "object-value",
            ],
            "objectCollection" => [
                [
                    "name" => "John",
                ],
                [
                    "name" => "Patrick",
                ],
            ],
        ]),
    ]);

$sms = $mailersend->sms->send($smsParams);

For the personalization of each text message, add the “personalization” object with each phone number and data objects as key: value pairs.

"personalization": [
      {
        "phone_number": "+19191234567",
        "data": {
          "name": "Dummy"
        }
      }
    ]

How to send SMS in bulk

You can send the same SMS content to multiple recipients (up to 50) by simply adding their numbers as an array. But if you want to send personalized messages to multiple recipients in a single request, you can do so by looping through recipients.

The example below creates a recipient list with personalization data, loops through each one and builds a text message, and then sends each SMS individually.

<?php
require __DIR__ . '/../vendor/autoload.php';

use MailerSend\MailerSend;
use MailerSend\Helpers\Builder\SmsParams;

$mailersend = new MailerSend([
    'api_key' => getenv('MAILERSEND_API_KEY')
]);

$recipients = [
    [
        'phone' => '+12065550102',
        'name' => 'Alice'
    ],
    [
        'phone' => '+12065550103',
        'name' => 'Bob'
    ]
];

foreach ($recipients as $recipient) {
    $text = "Hi {$recipient['name']}, your order has shipped!";

    $smsParams = (new SmsParams())
        ->setFrom('+1234567890')
        ->setTo([$recipient['phone']])
        ->setText($text);

    $mailersend->sms->send($smsParams);
}

On the Activity page, we can see that each message was delivered personalized with the recipient’s name.

Email activity with the message personalized for each recipient.

SMS response codes and error messages

When you send a request to send an SMS, MailerSend will check that your text message is valid. Your SMS will then either be queued or sent, and if found to be invalid, you’ll receive an error response. 

Sending queued response (202 accepted)

If there are no errors, you’ll receive the following HTTP response:

Response Code: 202 Accepted
Response Headers:
	Content-Type: text/plain; charset=utf-8
	X-SMS-Message-Id: 5e42957d51f1d94a1070a733
Response Body: [EMPTY]

If your from phone number cannot be validated, you’ll receive the following validation error message:

Response Code: 422 Unprocessable Entity
Response Headers:
	Content-Type: application/json

{
  "message": "The given data was invalid.",
  "errors": {
    "from": [
      "The from field contains an invalid number."
    ]
  }
}

Other MailerSend SMS delivery codes:

Code

Description

4301: malformed-invalid-encoding

The message contains unsupported characters. MailerSend cannot re-encode the message.

4302: malformed-invalid-from-number

The From number is not routable to a carrier or is invalid.

4303: malformed-invalid-to-number

The To number is not routable to a carrier or is invalid.

4403: rejected-forbidden-from-number

Messaging from the number is forbidden, most commonly because the number does not belong to MailerSend or the account.

4404: rejected-forbidden-to-number

Messaging to the number is forbidden. This could be because the number is not active, not enabled for messaging, or is an invalid number.

4412: media-content-invalid

The media content type is not supported.

4420: rejected-carrier-does-not-exist

The upstream carrier associated with the message does not exist in the MailerSend configuration.

4470: rejected-spam-detected

This message has been filtered and blocked by MailerSend as spam. 

Check out the complete list of SMS delivery codes and API response codes.

Best practices for sending SMS with PHP

1. Use a valid sender number

To ensure that your text messages are sent without errors and to provide the best possible experience for recipients, make sure you send your messages from a valid phone number. The number has to be a trial number or an active number on your account.

2. Use the E164 format

When entering phone numbers for senders and recipients, you must stick to the E164 format. This includes a maximum of 15 digits, and numbers start with a plus sign (+) followed by the country code (e.g., 1 for the U.S.) and the mobile number.

You can use Google’s libphonenumber library to validate and format phone numbers. 

composer require giggsey/libphonenumber-for-php

Here’s an example script that checks the number and outputs it in E164 format:

<?php
require __DIR__ . "/../vendor/autoload.php";

use libphonenumber\PhoneNumberUtil;
use libphonenumber\PhoneNumberFormat;
use libphonenumber\NumberParseException;

$phoneUtil = PhoneNumberUtil::getInstance();

// Change this number to test different inputs
$input = "+18974657286";

try {
    $number = $phoneUtil->parse($input, null);

    if ($phoneUtil->isValidNumber($number)) {
        $e164 = $phoneUtil->format($number, PhoneNumberFormat::E164);

        echo "Valid phone number\n";
        echo "E.164 format: " . $e164 . "\n";
    } else {
        echo "Invalid phone number\n";
    }
} catch (NumberParseException $e) {
    echo "Invalid phone number: could not parse input\n";
}

3. Remember your character limits

If using GSM-7 encoding, you can include up to 160 characters per segment. If using UCS-2 encoding, for languages such as Arabic, Chinese, Korean, or Cyrillic alphabet languages, etc., there is a limit of up to 70 characters per segment. UCS-2 encoding is also used for sending emojis. 

In MailerSend, there are no limits to the number of characters—or segments—you can send, however, you will be billed by segment. 

4. Provide unsubscribe instructions

To be in accordance with MailerSend’s terms of use and the Cellular Telecommunications Industry Association’s (CTIA) guidelines, you must provide a way for recipients to opt out of receiving your text messages. To do this, you can use the STOP command, which allows recipients to reply to your text with “STOP”, “Stop” or “stop” to opt out. 

Learn more about SMS compliance and head over to our guide on how to handle opt in and opt out for SMS.

MailerSend pricing

MailerSend’s flexible pricing makes it easy to get started with SMS and scale your sendings as necessary. Our Starter plan starts at just $28 a month for 50,000 emails and 100 SMS. After that, you’ll only pay for the additional SMS you send, at a rate of $1.40/100 SMS.

Learn more about SMS use cases:

Need more text messages? You can easily upgrade your plan to increase your SMS quota and get better pricing on additional SMS.

Check out our plans and pricing.

Sending SMS with PHP is simple

By using an advanced SMS API, ready-to-go PHP SDK, and the examples above, you can start sending personalized text messages directly to customers' phones in minutes. Just remember to follow technical best practices, obtain opt-in consent, and use a provider that follows CTIA guidelines. 

Amy Elliott
I’m Amy, Content Writer at MailerSend. As a child, I dreamt about writing a book and practiced by tearing pages from an A4 notepad and binding them with sugar paper. The book is pending but in the meantime, I love taking a deep dive into technical topics and sharing insights on email metrics and deliverability.