Skip to content
Keep your SMS messages from escaping into the wild during development, staging or stress tests.
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.


Build Status Coverage Status Code Climate Inline docs Gem Version Dependency Status

SMS safe provides a safety net while you're developing an application that sends SMS. It keeps SMS messages from escaping into the wild.

Inspired by MailSafe, it is essentially "MailSafe for SMS".

Once you've installed and configured this gem, you can rest assured that your app won't send SMS messages to external phone numbers.

Messages going to your own, internal phone numbers will still go through normally, however, anything else will either get sent to you instead (via SMS or Email), or discarded.


Gem: gem install sms_safe


Load the gem in the appropriate environments in your GemFile. For example, I'm loading this in Gemfile as:

gem "sms_safe", group: [:development, :staging]

IMPORTANT: Be sure not to load this in your production environment, otherwise, your SMS won't be sent to the proper recipients. In your test environment, you may or may not want this depending on how you are dealing with SMS right now.

We recommend using ActionTexter to send your SMS, which already provides for a very good way of switching SMS off in your test environment, while giving you testable objects that you can use to check your logic.


You should configure SmsSafe in the same initializer that you use for your SMS, so you can make sure that it runs after your Texter gem has been configured.

SmsSafe.configure do |config|
  config.internal_phone_numbers = ['+12223334444', '+447111222222']
  config.intercept_mechanism = :redirect
  config.redirect_target = '+12223334444'

SmsSafe.hook!(:action_texter) # or :twilio or :nexmo

Call hook! after setting the configuration for your texter gem.

The configuration specifies:

  • internal_phone_numbers: SMS sent to these numbers will be sent normally. These can be specified as a String, Regex, Proc, or an array of the same. Any phone number that doesn't match these is considered external, and its SMS will get intercepted. If left empty, all SMS will be intercepted.
  • intercept_mechanism: Whether to :redirect (default), :email or :discard the SMS sent to an external number.
  • redirect_target: If :redirecting, SMS will be sent to this number instead of the original recipient. Can be a String or a Proc
  • email_target: If :emailing, SMS will be sent as an e-mail to this e-mail address. Can be a String or a Proc
  • discard_delay: [ms] If :discarding, a delay this long will be introduced, for slightly more realistic performance characteristics.

Interception mechanisms

When an SMS is being sent to a phone number that is not recognized as internal, it gets intercepted and it will be processed according to the intercept_mechanism configured.


If you choose to :email or :discard instead of :redirecting, then when you send a message the return value from your texter gem can be nil if the SMS does get intercepted. You need to account for that, and consider it a successful send for your app logic.


SMS will be sent anyway, but to the number specified by redirect_target.

A string "(SmsSafe: #{original_phone_number})" will be added, so you know it was meant for a different number.


Instead of sending the SMS, an e-mail will be sent to the address specified by email_target, describing all the information about the SMS. This is useful in dev / staging as a less annoying alternative to SMS'ing yourself, and also for teams, since multiple people may end up having access to the e-mail, as opposed to an SMS.

You don't need to add any configuration for e-mailing to work. If you use Mail or ActionMailer, SmsSafe will magically use the configuration you set up for either.


In some cases, you just don't care, you simply don't want to be notified. This is particularly useful if you are doing load testing / stress testing, where millions of SMS / emails might end up being sent to you.

For this scenario, we include the discard_delay setting, which will make the "sending" take longer than a simple discard. You should set this to an average value that your SMS provider exhibits. This way, even if you are queueing SMS sending using Resque / DelayedJob, you can still check that, when dealing with a real load, your queue workers can keep up with the demand.

Using Procs for specifying whitelist or targets

In some cases, you'll need a bit more sophisticated logic than just matching on the phone number.

For example, in our staging environment, we want people that are signing up to receive the "verification" SMS, but we don't want them to accidentally SMS-invite their friends.

This does the job by deciding whether to allow based on the "reference" of the original message being intercepted:

SmsSafe.configure do |config|
  config.internal_phone_numbers = do |message| # Return true if it can go out, false if it needs to be intercepted
  config.intercept_mechanism = :discard

Supported Libraries

SmsSafe can currently hook into the following texter gems:

Of these 3, ActionTexter is the only one that provides useful functionality for automated testing, and functionality for interceptors / observers. It also works natively with both Twilio and Nexmo, so we recommend it extensively.

For Nexmo and Twilio Ruby, unfortunately, the way we hook is by monkey-patching them. This works, but it's not ideal, so we recommend using ActionTexter if you can.

If you would like the SmsSafe functionality but you use another SMS provider / gem, you can add the new provider and submit a Pull Request (see bottom of README), add the new provider to ActionTexter, or just ask, I'd like to extend this gem as much as possible.

Version Compatibility and Continuous Integration

Tested with Travis using Ruby 1.9.3, 2.0, 2.1.1, 2.1.2, 2.1.3 and 2.1.5, and against mail 2.6.3, 2.6.1, 2.5.4, 2.5.3 and 2.4.4.

To locally run tests do:

appraisal rake test

## Copyright

Copyright (c) 2014, 2015, Daniel Magliola

See LICENSE for details.

## Users

This gem is being used by:

- [MSTY](
- You? please, let us know if you are using this gem.

## Changelog

### Version 1.0.2 (Jan 28th, 2015)
- Changed dependency to action_texter to point to official gem again, now it's been updated.

### Version 1.0.1 (Jan 2nd, 2015)
- Made emails work automagically with either Mail or ActionMailer

### Version 1.0.0 (Jan 2nd, 2015)
- Newly released gem, supports ActionTexter, Nexmo and Twilio.
- Still waiting to make sure Mail configuration works transparently for both Mail and ActionMailer.
- Also waiting to figure out how to get Coveralls to recognize the true coverage (aka 100%)

## Contributing

1. Fork it
1. Create your feature branch (`git checkout -b my-new-feature`)
1. Code your thing
1. Write and run tests:
        bundle install
        appraisal rake test
1. Write documentation and make sure it looks good: yard server --reload
1. Add items to the changelog, in README.
1. Commit your changes (`git commit -am "Add some feature"`)
1. Push to the branch (`git push origin my-new-feature`)
1. Create new Pull Request
You can’t perform that action at this time.