diff --git a/bootstrap/README.txt b/bootstrap/README.txt
deleted file mode 100644
index 096db3f..0000000
--- a/bootstrap/README.txt
+++ /dev/null
@@ -1,96 +0,0 @@
-----------------------------
-An option for receiving SMS
-----------------------------
-
-To receive, parse and queue SMS for processing at a low bootstrap level.
-
-The include file (ab)uses the option to include a file at the cache level of
-bootstrap. 
-It provides a very basic routing system, which allows SMS provider modules
-to claim paths and allocate a parser class for the incoming request.
-The parsed SMS is then queued for later processing. By default the core
-database Drupal Queue will be used. To use an alternate queue and avoid 
-bootstrapping the database see the configuration under.
-
-------------------
-Using Drupal Queue
-------------------
-
-At its simplest add to your settings.php file the line:
-
-  // Path to the smsframework/bootstrap/sms_incoming.inc file to include.
-  $conf['cache_backends'][] = 'sites/all/module/smsframework/bootstrap/sms_incoming.inc';
-
-And set the variable 'sms_bootstrap_enabled' to TRUE. This can also be fixed in the
-settings.php file:
-
-  $conf['sms_bootstrap_enabled'] = TRUE;
-
-You will need a SMS provider module that implements the SmsParserInterface and offers this
-in 'sms_bootstrap_routes' variable.
-To avoid loading the variables you can also set this in the settings.php file. For example:
-
-  $conf['sms_bootstrap_routes'] = array(
-    'path/to/receive/sms' => array(
-      // Path to include the SmsParser class file.
-      'inc' => 'sites/all/modules/sms_provider/sms_provider.parser.inc',
-
-      // Parser class name.
-      'parser class' => 'SmsProviderParserClass',
-    ),
-  );
-
-------------------------
-Using an Alternate Queue
-------------------------
-
-If you are using a queue implementation of DrupalQueue that does not use the 
-database, you first must set all the variables above in you settings.php file.
-All variables required need to be in the settings.php to prevent the DB being
-loaded.
-
-Identify your queue with DrupalQueue by setting the appropriate variable. One
-of:
-
-  // If the queue is being used as the default.
-  $conf['queue_default_class'] = 'YourQueueClass';
-
-  // If you want to use the default queue name.
-  $conf['queue_class_sms_incoming'] = 'YourQueueClass';
-
-  // If you use another queue. Then also set 'name' => 'your_name' below.
-  $conf['queue_class_your_name'] = 'YourQueueClass';
-
-Then to identify you queue with any of these that maybe required:-
-
-  $conf['sms_bootstrap_queue'] = array(
-    // The path to include YourQueueClass. This is probably the only
-    // value that is absolutely required.
-    'inc' => 'path/to/required/queue.inc',
-
-    // To announce that the queue does not require the database.
-    // If other cache_backends are enabled, depending on order, and the
-    // 'page_cache_without_database' setting, the database may be loaded
-    // anyway. See documentation of your cache backend.
-    'require db' => FALSE,
-
-    // If not specified the default queue name is 'sms_incoming'.
-    'name' => 'queue_name',
-
-    // Default is a reliable queue.
-    'reliable' => TRUE,
-  );
-
----------------
-Developer notes
----------------
-
-If you are writing an SMS provider to support queueing, you will need to
-implement a parser class, preferably in a seperate include file. See:
-smsframework/sms.parser.inc for SmsParserInterface and the base
-SmsParserBase class.
-
-Automagically adding your route to the 'sms_bootstrap_routes' array, see
-example above, will aid users not setting the path and class in their
-settings.php $conf variables. Remember you have to include the absolute
-inc path (__DIR__, dirname(__FILE__) etc.)
diff --git a/bootstrap/sms_incoming.inc b/bootstrap/sms_incoming.inc
deleted file mode 100644
index 4e91315..0000000
--- a/bootstrap/sms_incoming.inc
+++ /dev/null
@@ -1,123 +0,0 @@
-<?php
-
-/**
- * @file
- *  Include file to (ab)use the cache router to accept and queue SMS.
- *
- *  See smsframework/bootstrap/README.txt for use instructions.
- */
-
-// Initial check of variable availability.
-sms_bootstrap_check_vars();
-
-// If it is route for incoming SMS, and bootstrap route is enabled, handle it
-// here.
-if (variable_get('sms_bootstrap_enabled', FALSE) && ($route = sms_bootstrap_load_route())) {
-  // Yes it needs standard Drupal core dir structure.
-  require_once DRUPAL_ROOT . '/modules/system/system.queue.inc';
-  // Also if you move this file relative to the rest of sms framework.
-  require dirname(__FILE__) . '/../sms.parser.inc';
-  // Include the absolute path to the file including the SMS provider class.
-  require $route['inc'];
-
-  // Check access to the incoming parser.
-  $access = $route['parser class']::checkAccess(ip_address(), $_REQUEST);
-  if ($access !== TRUE) {
-    watchdog('access denied', request_path(), NULL, WATCHDOG_WARNING);
-    sms_bootstrap_response($access);
-    exit;
-  }
-
-  // Parse request with class defined by the SMS provider for the route.
-  $parser = new $route['parser class']($_REQUEST);
-  $parser->parseRequest();
-
-  $queue = sms_bootstrap_load_queue();
-
-  // Add parsed item to the queue.
-  if ($parser->getNumber() || $parser->getMessage()) {
-    // @todo change so the full class can be serialized/deserialized.
-    $item = array(
-      'number' => $parser->getNumber(),
-      'message' => $parser->getMessage(),
-      'options' => $parser->getOptions(),
-    );
-    $queue->createItem($item);
-  }
-
-  sms_bootstrap_response($parser->getResponse);
-  exit;
-}
-
-/**
- * Check to see if the request path is a route register to be handled.
- */
-function sms_bootstrap_load_route() {
-  if (! $routes = variable_get('sms_bootstrap_routes', '')) {
-    // No routes defined. Allow core to continue.
-    return FALSE;
-  }
-
-  if (isset($routes[request_path()])) {
-    return $routes[request_path()];
-  }
-
-  return FALSE;
-}
-
-/**
- * Load and return the appropriate queue.
- *
- * If an alternate queue system is configured. Ensure a required include
- * file is loaded. Use Drupal variables 'queue_class' . $name, or
- * 'queue_default_class' to define the implementation of DrupalQueueInterface
- * to load.
- *
- * Set 'sms_bootstrap_queue' in settings.php if you don't rely on the db.
- */
-function sms_bootstrap_load_queue() {
- $queue_info = variable_get('sms_bootstrap_queue', array());
-  if (empty($queue_info['require db']) || $queue_info['required db']) {
-    // The queue requires the db to be bootstraped, even if all the
-    // variables have been supplied so far from settings.php.
-    // Default DrupalSystemQueue requires DB. Set your $queue_info['require db']
-    // to FALSE if you don't need it.
-    drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE, FALSE);
-  }
-  if (! empty($queue_info['inc'])) {
-    require($queue_info['inc']);
-  }
-  $name = empty($queue_info['name']) ? 'sms_incoming' : $queue_info['name'];
-  $reliable = empty($queue_info['reliable']) ? TRUE : $queue_info['reliable'];
-  $queue = DrupalQueue::get($name, $reliable);
-  $queue->createQueue();
-
-  return $queue;
-}
-
-/**
- * If either of the required variables are not set load variables.
- *
- * Avoid this by setting both 'sms_bootstrap_routes' and 'sms_bootstrap_enabled'
- * in your settings.php file.
- */
-function sms_bootstrap_check_vars() {
-  if (variable_get('sms_bootstrap_routes', '') === '' || variable_get('sms_bootstrap_enabled', '') === '') {
-    drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES, FALSE);
-  }
-}
-
-/**
- * Send a HTTP response.
- *
- * @param array $response
- *   array('headers' => array('name' => 'value'), 'body' => 'text')
- */
-function sms_bootstrap_response($response) {
-  // Allow SMS provider to add content to response.
-  foreach ($response['headers'] as $name => $value) {
-    drupal_add_http_header($name, $value);
-  }
-  drupal_send_headers();
-  print $response['body'];
-}
diff --git a/modules/sms_devel/sms_devel.virtualgw.inc b/modules/sms_devel/sms_devel.virtualgw.inc
index d106d7a..ee383f7 100644
--- a/modules/sms_devel/sms_devel.virtualgw.inc
+++ b/modules/sms_devel/sms_devel.virtualgw.inc
@@ -14,6 +14,7 @@
  "in_number" to simply "gw_number".
  */
 
+use Drupal\sms\Entity\SmsMessage;
 use Drupal\sms\Plugin\SmsGatewayPluginInterface;
 use Drupal\sms\Message\SmsMessageInterface;
 
@@ -80,19 +81,32 @@ function sms_devel_virtualgw_send($number, $message, $options) {
  *   Array of options.
  */
 function sms_devel_virtualgw_receiver($number = NULL, $message = NULL, $options = array()) {
+  $sms_message = SmsMessage::create();
+
   // Handle HTTP requests rather than direct function calls
-  if ($number === NULL) {
-    $number  = $_REQUEST['number'];
-    $message = (array_key_exists('message', $_REQUEST)) ? $_REQUEST['message'] : 'NO_MESSAGE';
-    $options['gw_number'] = (array_key_exists('gw_number', $_REQUEST)) ? $_REQUEST['gw_number'] : 'NO_GW_NUMBER';
-    $options['reference'] = (array_key_exists('reference', $_REQUEST)) ? $_REQUEST['reference'] : 'NO_REFERENCE';
+  if (isset($number)) {
+    $sms_message->addRecipient($number);
+    $sms_message->setMessage($message);
+  }
+  else {
+    $sms_message->addRecipient($_REQUEST['number']);
+    $sms_message->setMessage((array_key_exists('message', $_REQUEST)) ? $_REQUEST['message'] : 'NO_MESSAGE');
+    $sms_message->setOption('gw_number', (array_key_exists('gw_number', $_REQUEST)) ? $_REQUEST['gw_number'] : 'NO_GW_NUMBER');
+    $sms_message->setOption('reference', (array_key_exists('reference', $_REQUEST)) ? $_REQUEST['reference'] : 'NO_REFERENCE');
   }
 
   // Write log record for incoming message
-  sms_devel_virtualgw_log_insert(SMS_DEVEL_VIRTUALGW_TYPE_IN, $number, $message, $options);
-
-  // Call SMS Framework incoming message handler
-  sms_incoming($number, $message, $options);
+  $recipients = $sms_message->getRecipients();
+  sms_devel_virtualgw_log_insert(
+    SMS_DEVEL_VIRTUALGW_TYPE_IN,
+    reset($recipients),
+    $sms_message->getMessage(),
+    $sms_message->getOptions())
+  ;
+
+  /** @var \Drupal\sms\Provider\SmsProviderInterface $provider */
+  $provider = \Drupal::service('sms_provider');
+  $provider->incoming($sms_message);
 }
 
 
diff --git a/modules/sms_devel/src/Form/SendForm.php b/modules/sms_devel/src/Form/SendForm.php
index f2bbc55..4a29260 100644
--- a/modules/sms_devel/src/Form/SendForm.php
+++ b/modules/sms_devel/src/Form/SendForm.php
@@ -9,6 +9,7 @@ namespace Drupal\sms_devel\Form;
 
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\sms\Message\SmsMessage;
 
 class SendForm extends FormBase {
 
@@ -66,25 +67,27 @@ class SendForm extends FormBase {
    * {@inheritdoc}
    */
   function submitForm(array &$form, FormStateInterface $form_state) {
+    $phone_number = $form_state->getValue('number');
+    $message = $form_state->getValue('message');
+    $t_args = [
+      '@number'  => $phone_number,
+      '@message' => $message,
+    ];
+
     if ($form_state->getTriggeringElement()['#value'] === $form_state->getValue('submit')) {
       sms_send_form_submit($form, $form_state);
-      // Display a message to the user.
-      drupal_set_message($this->t("Form submitted ok for number @number and message: @message",
-        [
-          '@number'  => $form_state->getValue('number'),
-          '@message' => $form_state->getValue('message')
-        ]));
+      drupal_set_message($this->t('Form submitted ok for number @number and message: @message', $t_args));
     }
     elseif ($form_state->getTriggeringElement()['#value'] === $form_state->getValue('receive')) {
-      // Display a message to the user.
-      $number = $form_state->getValue('number');
-      $message = $form_state->getValue('message');
-      sms_incoming($number, $message);
-      drupal_set_message($this->t("Message received from number @number and message: @message",
-        [
-          '@number'  => $form_state->getValue('number'),
-          '@message' => $form_state->getValue('message')
-        ]));
+      $sms_message = (new SmsMessage())
+        ->addRecipient($phone_number)
+        ->setMessage($message);
+
+      /** @var \Drupal\sms\Provider\SmsProviderInterface $provider */
+      $provider = \Drupal::service('sms_provider');
+      $provider->incoming($sms_message);
+
+      drupal_set_message($this->t('Message received from number @number and message: @message', $t_args));
     }
   }
 
diff --git a/sms.module b/sms.module
index da2b719..fcb396e 100644
--- a/sms.module
+++ b/sms.module
@@ -172,42 +172,6 @@ function sms_send($number, $message, array $options = array()) {
 }
 
 /**
- * Queue worker callback for queued incoming messages.
- *
- * @param array $item
- *   An array containing arguments for sending queued message.
- *
- * @see sms_cron_queue_info().
- */
-function sms_incoming_queue_worker(array $item) {
-  sms_incoming($item['number'], $item['message'], $item['options']);
-}
-
-/**
- * Handles incoming messages.
- *
- * Allows gateways modules to pass messages in a standard format for processing.
- * Every implementation of hook_sms_incoming() will be invoked by this method.
- *
- * Additionally, 'sms_incoming' rules event will be invoked if rules module is
- * enabled.
- *
- * @param string $number
- *   The sender's mobile number.
- * @param string $message
- *   The content of the text message.
- * @param array $options
- *   An array of additional options.
- *
- * @deprecated use \Drupal\sms\Provider\SmsProviderInterface::incoming() instead.
- */
-function sms_incoming($number, $message, array $options = array()) {
-  $sender = isset($options['sender']) ? $options['sender'] : '';
-  $sms = new SmsMessage($sender, explode(',', $number), $message, $options, \Drupal::currentUser()->id());
-  \Drupal::service('sms_provider')->incoming($sms);
-}
-
-/**
  * Handles responses to message transactions.
  *
  * @see \Drupal\sms\Gateway\SmsProviderInterface::receipt
