Over the years SMS has become a much less important way of communication, but it can still be useful for receiving important system notifications.

Common reasons to be using SMS in 2023:

  • Identity verification (confirm phone number via SMS)
  • Important appointment reminders (doctors appointment)
  • 2 Factor Authentication via SMS (my grandma does not use 2FA apps)

For example, when I was creating a chatgpt account, it required a confirmed phone number. Most likely to decrease the amount of bots:


Twilio offers a very easy way to send SMS using Rails.

Access Twilio API keys #

After creating an account, navigate to https://console.twilio.com


Save twilio credentials in your apps credentials.yml:

  account_sid: AC714f90d7750d7cf2
  auth_token: c8671c5e8233b0
  from_phone_number: "+18305801212"
  dummy_to_phone_number: "+48537623523"

If you send messages while in trial mode, you must first verify your ‘To’ phone number (dummy_to_phone_number). Ensure that your phone number is in a valid geo & is verified.

Send SMS with Twilio in a Rails app #

Install gem 'twilio-ruby':

bundle add twilio-ruby

Create a Service that you can call in your app:

# app/services/twilio/send_sms_service.rb
module Twilio
  class SendSmsService
    require 'twilio-ruby'

    def call(body, to_phone_number)
      account_sid = Rails.application.config_for(:settings).dig(:credentials, :twilio, :account_sid)
      auth_token = Rails.application.config_for(:settings).dig(:credentials, :twilio, :auth_token)
      from_phone_number = Rails.application.config_for(:settings).dig(:credentials, :twilio, :from_phone_number)
      dummy_to_phone_number = Rails.application.config_for(:settings).dig(:credentials, :twilio, :dummy_to_phone_number)

        @client = Twilio::REST::Client.new account_sid, auth_token
        message = @client.messages.create(
                           from: from_phone_number,
                           to: to(to_phone_number),
                           #  media_url: ['https://demo.twilio.com/owl.png'] # MMS example
        puts message.sid
      rescue Twilio::REST::TwilioError => exception
        puts exception.message


    def to(to_phone_number)
      return dummy_to_phone_number if Rails.env.development?


Call the service and send an SMS:

body = 'some text'
to_phone_number = '+38050554470367'
Twilio::SendSmsService.new.call(body, to_phone_number)

Testing with Rspec #

Assuming from_phone_number = 18305803384, the test and stubbed Webmock request could look like this:

# spec/services/send_sms_service_spec.rb
require 'rails_helper'

RSpec.describe Twilio::SendSmsService do
  let(:body) { 'lorem ipsum' }
  let(:to_phone_number) { '+123456789' }
  let(:twilio_api_url) { "https://api.twilio.com/2010-04-01/Accounts/#{Rails.application.config_for(:settings).dig(:credentials, :twilio, :account_sid)}/Messages.json" }
  subject(:call) { described_class.new.call(body, to_phone_number) }

  before do
    stub_request(:post, twilio_api_url).to_return(status: 200)

  context 'calls twilio api' do
    it 'sends request' do
      expect(WebMock).to have_requested(:post, twilio_api_url).with(body: 'Body=lorem+ipsum&From=%2B18305803384&To=%2B123456789')

Final thoughts, next steps #

Ideally, before sending transactional SMS messages, I would build a mechanism for the user to verify his phone number.

Here’s how it would work:

  1. User inputs his phone number.
  2. We generate random 6-digit token and send it to the user via SMS.
  3. User receives SMS, submits token in a form.
  4. If the token that the user submits is correct, we mark his phone number as verified.

Also, we might be able to track if an SMS has been delivered on Twilio’s side. Than we would mark the phone number as invalid if the SMS is not deliverable.

We can also try to validate the to_phone_number via Twilio lookup API.

It all depends on your unique usecase and how far your are willing to go :)