DEV Community

Cover image for Send SMS with Twilio in Rails
Yaroslav Shmarov
Yaroslav Shmarov

Posted on • Originally published at on

Send SMS with Twilio in Rails

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


Save twilio credentials in your apps credentials.yml:

  account_sid: AC714f90d7750d7cf2
  auth_token: c8671c5e8233b0
  from_phone_number: "+18305801212"
  dummy_to_phone_number: "+48537623523"
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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 = account_sid, auth_token
        message = @client.messages.create(
                           from: from_phone_number,
                           to: to(to_phone_number),
                           # media_url: [''] # 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?

Enter fullscreen mode Exit fullscreen mode

Call the service and send an SMS:

body = 'some text'
to_phone_number = '+38050554470367', to_phone_number)
Enter fullscreen mode Exit fullscreen mode

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) { "{Rails.application.config_for(:settings).dig(:credentials, :twilio, :account_sid)}/Messages.json" }
  subject(:call) {, 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')
Enter fullscreen mode Exit fullscreen mode

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 :)

Top comments (0)