diff --git a/sms.module b/sms.module
index 7ee6f9c..897a0ec 100644
--- a/sms.module
+++ b/sms.module
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * The core of the SMS Framework. Provides gateway managment and API for
+ * The core of the SMS Framework. Provides gateway management and API for
  * sending and receiving SMS messages.
  */
 
@@ -12,37 +12,14 @@ define('SMS_DIR_OUT',   1);
 define('SMS_DIR_IN',    2);
 define('SMS_DIR_ALL',   4);
 
-// Message status codes
-// 0=Unknown, 2xx=Positive, 3xx=Positive/Neutral (context-dependent), 4xx=Negative
-define('SMS_MSG_STATUS_UNKNOWN',      0);
-define('SMS_MSG_STATUS_OK',         200);
-define('SMS_MSG_STATUS_DELIVERED',  202);
-define('SMS_MSG_STATUS_QUEUED',     302);
-define('SMS_MSG_STATUS_ERROR',      400);
-define('SMS_MSG_STATUS_NOCREDIT',   402);
-define('SMS_MSG_STATUS_EXPIRED',    408);
-
-// Gateway response codes
-// 0=Unknown, 2xx=Positive, 4xx=Negative(likely client err), 5xx=Negative(likely gateway err)
-define('SMS_GW_UNKNOWN_STATUS',      0);
-define('SMS_GW_OK',                200);
-define('SMS_GW_ERR_AUTH',          401);
-define('SMS_GW_ERR_INVALID_CALL',  400);
-define('SMS_GW_ERR_NOT_FOUND',     404);
-define('SMS_GW_ERR_MSG_LIMITS',    413);
-define('SMS_GW_ERR_MSG_ROUTING',   502);
-define('SMS_GW_ERR_MSG_QUEUING',   408);
-define('SMS_GW_ERR_MSG_OTHER',     409);
-define('SMS_GW_ERR_SRC_NUMBER',    415);
-define('SMS_GW_ERR_DEST_NUMBER',   416);
-define('SMS_GW_ERR_CREDIT',        402);
-define('SMS_GW_ERR_OTHER',         500);
-
 //
 define('SMS_CARRIER_DEFAULT', 0);
 define('SMS_CARRIER_OVERRIDDEN', 1);
 define('SMS_CARRIER_NORMAL', 3);
 
+use Drupal\sms\Gateway\GatewayInterface;
+use Drupal\sms\Message\Message;
+
 /**
  * Implements hook_permission().
  */
@@ -92,47 +69,8 @@ function sms_cron_queue_info() {
  *   An array of dditional properties as defined by gateway modules.
  */
 function sms_send($number, $message, $options = array()) {
-  $gateway = sms_default_gateway();
-
-  foreach (\Drupal::moduleHandler()->getImplementations('sms_send') as $module) {
-    $function = $module . '_sms_send';
-    $function($number, $message, $options, $gateway);
-  }
-
-  $response = NULL;
-  if (isset($gateway['send']) && function_exists($gateway['send'])) {
-    $response = $gateway['send']($number, $message, $options);
-  }
-  $result = sms_handle_result($response, $number, $message);
-
-  // Post process hook
-  foreach (\Drupal::moduleHandler()->getImplementations('sms_send_process') as $module) {
-    $function = $module . '_sms_send_process';
-    $function('post process', $number, $message, $options, $gateway, $result);
-  }
-
-  return $result;
-}
-
-/**
- * Handle the response back from the sms gateway.
- */
-function sms_handle_result($result, $number, $message) {
-  if ($result['status']) {
-    return TRUE;
-  }
-  else {
-    $error_message = 'Sending SMS to %number failed.';
-    $variables['%number'] = $number;
-    if ($result['message']) {
-      $error_message .= ' The gateway said ' . $result['message'];
-      if (!empty($result['variables'])) {
-        $variables = array_merge($variables, $result['variables']);
-      }
-    }
-    watchdog('sms', $error_message, $variables, WATCHDOG_ERROR);
-    return FALSE;
-  }
+  $sms = new Message($options['sender'], explode(',', $number), $message, $options);
+  return \Drupal::service('sms.provider')->send($sms, $options);
 }
 
 /**
@@ -186,7 +124,7 @@ function sms_incoming($number, $message, $options = array()) {
  * @param array $options
  * Extended options passed by the receipt receiver.
  */
-function sms_receipt($number, $reference, $message_status = SMS_GW_UNKNOWN_STATUS, $options = array()) {
+function sms_receipt($number, $reference, $message_status = GatewayInterface::STATUS_UNKNOWN, $options = array()) {
   // Execute three phases
   \Drupal::moduleHandler()->invokeAll('sms_receipt', 'pre process', $number, $reference, $message_status, $options);
   \Drupal::moduleHandler()->invokeAll('sms_receipt', 'process', $number, $reference, $message_status, $options);
@@ -195,100 +133,65 @@ function sms_receipt($number, $reference, $message_status = SMS_GW_UNKNOWN_STATU
 
 /**
  * Returns the current default gateway.
+ *
+ * @return \Drupal\sms\Gateway\GatewayInterface
  */
 function sms_default_gateway() {
-  return sms_gateways('gateway', sms_default_gateway_id());
-}
-
-function sms_default_gateway_id() {
-  return \Drupal::config('sms.settings')->get('default_gateway');
+  return \Drupal::service('plugin.manager.smsgateway')->getDefaultGateway();
 }
 
 /**
- * Implements hook_gateway_info().
- */
-function sms_gateway_info() {
-  return array(
-    'log' => array(
-      'name' => t('Log only'),
-      'send' => 'sms_send_log',
-    ),
-  );
-}
-
-/**
- * Log sms message.
+ * Returns the identifier for the current default gateway.
  *
- * @param $number
- *   Mobile numbers message sent to.
- * @param $message
- *   Message sent.
- * @param $options
- *   Associative array of options passed to gateway.
+ * @return string
  */
-function sms_send_log($number, $message, $options) {
-  watchdog('sms', 'SMS message sent to %number with the text: @message', array('%number' => $number, '@message' => $message), WATCHDOG_INFO);
-  return array('status' => TRUE);
-}
-
-
-/**
- * SMS gateway menutitle callback.
- */
-function sms_admin_gateway_title($gateway_id) {
-  $gateway = sms_gateways('gateway', $gateway_id);
-  return sprintf('%s gateway', $gateway['name']);
+function sms_default_gateway_id() {
+  return \Drupal::config('sms.settings')->get('default_gateway');
 }
 
 /**
  * Get a list of all gateways
  *
- * @param $op
+ * @param string $op
  *   The format in which to return the list. When set to 'gateway' or 'name',
  *   only the specified gateway is returned. When set to 'gateways' or 'names',
  *   all gateways are returned.
  *
- * @param $gateway
- *   A gateway identifier string that indicates the gateway to return. Leave at default
- *   value (NULL) to return all gateways.
+ * @param string $gateway
+ *   A gateway identifier string that indicates the gateway to return. Leave at
+ *   default value (NULL) to return all gateways.
  *
- * @return
+ * @return array|\Drupal\sms\Gateway\GatewayInterface
  *   Either an array of all gateways or a single gateway, in a variable format.
+ *
+ * @deprecated as of 8.x-1.x. Use GatewayManager:: methods instead.
+ * @code
+ *   Drupal::service('plugin.manager.smsgateway')->getAvailableGateways();
+ *   Drupal::service('plugin.manager.smsgateway')->getEnabledGateways();
+ *   Drupal::service('plugin.manager.smsgateway')->getDefaultGateway();
+ *   Drupal::service('plugin.manager.smsgateway')->getGateway($name);
+ * @endcode
  */
 function sms_gateways($op = 'gateways', $gateway = NULL) {
-  list($_gateways, $_names) = _gateways_build();
+  /** @var \Drupal\sms\Gateway\GatewayManagerInterface $gateway_manager */
+  $gateway_manager = \Drupal::service('plugin.manager.smsgateway');
 
   switch ($op) {
-    case 'gateways':
-      return $_gateways;
     case 'gateway':
-      $return = empty($_gateways[$gateway]) ? array() : $_gateways[$gateway];
-      $return['identifier'] = $gateway;
-      return $return;
+      return $gateway_manager->getGateway($gateway) ? : array();
     case 'names':
+      $_names = array();
+      foreach ($gateway_manager->getAvailableGateways() as $id => $gw) {
+        $_names[$id] = $gw->getLabel();
+      }
       return $_names;
     case 'name':
-      return $_names[$gateway];
-  }
-}
-
-function _gateways_build() {
-  // @todo Implement caching here
-  $_gateways = array();
-  $_names = array();
-
-  $gateway_array = \Drupal::moduleHandler()->invokeAll('gateway_info');
-  $config = \Drupal::config('sms.settings');
-  $settings = $config->get('gateway_settings');
-  foreach ($gateway_array as $identifier => $info) {
-    $info['configuration'] = $settings ? $settings[$identifier] : array();
-    $_gateways[$identifier] = $info;
-    $_names[$identifier] = $info['name'];
+      $gw = $gateway_manager->getGateway($gateway);
+      return ($gw) ? $gw->getLabel() : '';
+    case 'gateways':
+    default:
+      return $gateway_manager->getAvailableGateways();
   }
-
-  asort($_names);
-
-  return array($_gateways, $_names);
 }
 
 /**
@@ -315,10 +218,9 @@ function sms_send_form($required = FALSE) {
   );
 
   // Add gateway defined fields
-  if (!empty($gateway['send form']) && function_exists($gateway['send form'])) {
-    $form['gateway']['#tree'] = TRUE;
-    $form['gateway'] = array_merge($gateway['send form']($required), $form['gateway']);
-  }
+  $form_state = array();
+  $form['gateway']['#tree'] = TRUE;
+  $form['gateway'] = array_merge($gateway->sendForm($form, $form_state), $form['gateway']);
 
   return $form;
 }
diff --git a/sms.services.yml b/sms.services.yml
new file mode 100644
index 0000000..c5e4aa5
--- /dev/null
+++ b/sms.services.yml
@@ -0,0 +1,8 @@
+services:
+  sms.provider:
+    class: Drupal\sms\Sms
+    arguments: ['@plugin.manager.smsgateway', '@module_handler']
+
+  plugin.manager.smsgateway:
+    class: Drupal\sms\Gateway\GatewayManager
+    arguments: ['@container.namespaces', '@config.factory', '@module_handler']
diff --git a/src/Annotation/SmsGateway.php b/src/Annotation/SmsGateway.php
new file mode 100644
index 0000000..1cf32b0
--- /dev/null
+++ b/src/Annotation/SmsGateway.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\sms\Annotation\SmsGateway
+ */
+
+namespace Drupal\sms\Annotation;
+
+use Drupal\Component\Annotation\Plugin;
+
+/**
+ * Defines SmsGateway Annotation object.
+ *
+ * @Annotation
+ */
+class SmsGateway extends Plugin {
+  /**
+   * The machine name of the sms gateway.
+   *
+   * @var string
+   */
+  protected $id;
+
+  /**
+   * Translated user-readable label.
+   * @var string
+   */
+  protected $label;
+
+  /**
+   * A boolean flag to determine if the gateway is configurable.
+   *
+   * @var bool
+   */
+  protected $configurable;
+}
diff --git a/src/Gateway/GatewayBase.php b/src/Gateway/GatewayBase.php
new file mode 100644
index 0000000..75be6e4
--- /dev/null
+++ b/src/Gateway/GatewayBase.php
@@ -0,0 +1,112 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\sms\Gateway\GatewayBase
+ */
+
+namespace Drupal\sms\Gateway;
+
+use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Plugin\PluginBase;
+
+/**
+ * Base class for sms gateway plugins.
+ */
+abstract class GatewayBase extends PluginBase implements GatewayInterface {
+  /**
+   * Construct a new SmsGateway plugin
+   *
+   * @param array
+   *   The configuration to use and build the sms gateway.
+   * @param string
+   *   The gateway id.
+   * @param mixed
+   *   The gateway plugin definition.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    $this->configuration = $this->configuration + $this->defaultConfiguration();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIdentifier() {
+    return $this->pluginDefinition['id'];
+  }
+
+  /**
+  /**
+   * {@inheritdoc}
+   */
+  public function getName() {
+    return $this->getLabel();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getLabel() {
+    return $this->pluginDefinition['label'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfiguration() {
+    return $this->configuration;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setConfiguration(array $configuration) {
+    $this->configuration = $configuration;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function defaultConfiguration() {
+    return array(
+      'use_ssl' => FALSE,
+      'send_method' => 'HTTP_POST',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isConfigurable() {
+    return $this->pluginDefinition['configurable'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildConfigurationForm(array $form, array &$form_state) {
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateConfigurationForm(array &$form, array &$form_state) {
+    return;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitConfigurationForm(array &$form, array &$form_state) {
+    return;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function sendForm(array &$form, array &$form_state) {
+    return array();
+  }
+}
\ No newline at end of file
diff --git a/src/Gateway/GatewayDefaultImpl.php b/src/Gateway/GatewayDefaultImpl.php
new file mode 100644
index 0000000..7a94328
--- /dev/null
+++ b/src/Gateway/GatewayDefaultImpl.php
@@ -0,0 +1,321 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\sms\Plugin\Gateway\GatewayDefaultImpl
+ */
+
+namespace Drupal\sms\Gateway;
+
+use Drupal\sms\Message\Message;
+use Drupal\sms\Message\MessageInterface;
+use Drupal\sms\Message\MessageResult;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Provides a default implementation of the Gateway interface with additional
+ * helper functions.
+ *
+ * Most gateways should subclass this for easier implementations.
+ */
+abstract class GatewayDefaultImpl extends GatewayBase {
+  /**
+   * {@inheritdoc}
+   */
+  public function send(MessageInterface $sms, array $options) {
+    // Wrapper method for sending messages.
+    // Provides basic cleanup functionality prior to passing onto gateway send
+    // command. Subclasses will implement additional logic in the doSend() method
+    // and also call the doCommand('send') method to dispatch messages.
+
+    // Call subclass implementation to process sending.
+    $res = $this->doSend($sms, $options);
+
+    // Invoke sms framework message receipt handlers
+    // @todo Need to re-look this implementation
+    foreach ($res as $num => $response) {
+      @$options += array(
+        'gateway_message_status' => $response['error map'],
+        'gateway_message_status_text' => $response['error'],
+        'gateway_message_status_original' => $response['error code'],
+        'gateway' => $this->getName(),
+      );
+      @sms_receipt($num, $response['message id'], $response['message status'], $options);
+    }
+    return $res;
+  }
+
+
+  /**
+   * {@inheritdoc}
+   */
+  public function balance() {
+    $result = $this->doCommand('credits', array());
+    return isset($result['credit_balance']) ? $result['credit_balance'] : 0;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deliveryReport(Request $request) {
+    return;
+  }
+
+  /**
+   * Provide delivery reports return path for this gateway
+   * @todo Needs work.
+   */
+  protected function deliveryPath($absolute=TRUE) {
+    $path = 'sms/deliveryreport/' . $this->getName();
+    if ($absolute) {
+      $path = url($path, array('absolute' => TRUE));
+    }
+    return $path;
+  }
+
+  /**
+   * Tests the gateway.
+   *
+   * @param array $config
+   *    Optional configuration parameters to test gateway with.
+   * @return TRUE / FALSE if gateway is through
+   */
+  function test(array $config = array()) {
+    $result = $this->doCommand('test', array(), $config);
+    return $result['status'];
+  }
+
+  /**
+   * Handles the low-level connection for sending messages.
+   *
+   * This method implicitly handles the splitting of messages into smaller
+   * batches if the number of recipients are too much for a standard HTTP-GET
+   * or HTTP-POST payload.
+   *
+   * @see doSplitSend()
+   *
+   * @param Message $message
+   *   The sms message to be sent.
+   * @param $options
+   *   Additional options.
+   * @return \Drupal\sms\Message\MessageResult
+   *   The result of the sms messaging operation.
+   *
+   * @return array(
+   *     'status'  => TRUE | FALSE,
+   *     'message' => '<message to display if status above is FALSE>',
+   *     'report'  => array(
+   *       '<number>' => array(
+   *         'status' => TRUE | FALSE   // Essentially TRUE if there is a message id
+   *         'message_id' => '<message id>',
+   *         'error_code' => '<sms framework error code>',
+   *         'error_message' => '<sms framework error message>',
+   *         'gateway_error_code' => '<gateway error code>',
+   *         'gateway_error_message' => '<gateway error message>'
+   *       ),
+   *     'credit_used' => '<credits used>',
+   *     'credit_balance' => '<credits remaining>',
+   *   );
+   *
+   * Notes: 'status' of TRUE means successful communication with the sms server and success in message request. Failure of
+   *  individual messages will be captured in the message report status for that number.
+   */
+  protected function doSend(Message $message, array $options) {
+    return $this->doSplitSend($message, $options);
+  }
+
+  /**
+   * Splits and sends messages in batches to recipients.
+   *
+   * This method splits messages into smaller batches to avoid exceeding HTTP-GET
+   * and HTTP-POST data size limits which may cause timeouts, truncated messages,
+   * and other sorts of wierd behavior depending on the web server.
+   *
+   * @param \Drupal\sms\Message\Message $sms
+   *   The message to be sent.
+   * @param array $options
+   *   Options to be applied while processing this sms.
+   * @param $maxsize int
+   *   Optional - maximum size of each batch to send.
+   * @return \Drupal\sms\Message\MessageResult
+   *   The composite MessageResult object.
+   */
+  protected function doSplitSend(Message $sms, array $options, $maxsize = 400) {
+    // Initialize the composite results array.
+    $all_res = array(
+      'status' => FALSE,
+      'error_message' => '',
+      'credit_used' => 0,
+      'credit_balance' => 0,
+      'report' => array(),
+    );
+    $recipients = $sms->getRecipients();
+    while (count($recipients) > 0) {
+      $this_batch = array_slice($recipients, 0, $maxsize);
+      $recipients = array_slice($recipients, $maxsize);
+      if (!empty($this_batch)) {
+        $res = $this->doCommand('send', array('recipients' => $this_batch, 'message' => $sms->getMessage()), $options);
+        // Combine $res with existing $all_res
+        @$all_res['status'] |= $res['status'];
+        @$all_res['error_message'] .= "\n" . $res['message'];
+        @$all_res['credit_used'] += $res['credit_used'];
+        @$all_res['credit_balance'] = $res['credit_balance'];
+        @$all_res['report'] += (array)$res['report'];
+      }
+    }
+    return new MessageResult($all_res);
+  }
+
+  /**
+   * Generates random message id's for gateways that don't autogenerate
+   */
+  protected function randomID() {
+    if (!isset($this->sessid)) {
+      $this->sessid = str_pad(rand(0, 99), 2, '0', STR_PAD_LEFT);
+    }
+    return time() . $this->sessid . str_pad(rand(0, 99999), 5, '0', STR_PAD_LEFT);
+  }
+
+  /**
+   * Handles the low-level transmission of messages.
+   *
+   * @param string $command
+   *   The command to be executed.
+   * @param array $data
+   *   An array containing the data pertaining to the message. Information that
+   *   can be in this array is as follows:
+   *   - recipients: An array of recipient numbers.
+   *   - message: The sms message to be dispatched.
+   *   -
+   * @param array $options
+   *   Optional - additional options for sending the message.
+   *
+   * @see \Drupal\sms\Gateway\GatewayInterface::send() for structure of return value
+   */
+  abstract protected function doCommand($command, array $data, array $options = array());
+
+  /**
+   * Cleans up message and removes non-compatible characters.
+   *
+   * @param string $message
+   *   The message to be cleaned up.
+   * @return string
+   *   The cleaned up message.
+   */
+  protected function cleanMessage($message) {
+    $search = str_split('ëí`ìî');
+    $replace = str_split('\'\'\'""');
+    $message = str_replace($search, $replace, $message);
+    $message = urlencode($message);
+    return $message;
+  }
+
+  /**
+   * Cleans up sender id and removes non-compatible characters.
+   *
+   * @param string $sender
+   *   The sender id to be cleaned up.
+   * @return string
+   *   The cleaned up sender.
+   */
+  protected function cleanSender($sender) {
+    return str_replace(' ', '', urlencode(substr($sender, 0, 12)));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function defaultConfiguration() {
+    return array(
+      'ssl' => '',
+      'server' => '',
+      'username' => '',
+      'password' => '',
+      'method' => '',
+    ) + parent::defaultConfiguration();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildConfigurationForm(array $form, array &$form_state) {
+    $config = $this->getConfiguration();
+
+    $t_args = array(
+      '@name' => $this->getName(),
+      '@label' => $this->getLabel(),
+    );
+
+    $form['balance'] = array(
+      '#type' => 'item',
+      '#title' => $this->t('Current balance'),
+      '#markup' => $this->balance(),
+    );
+    $form['method'] = array(
+      '#type' => 'radios',
+      '#title' => $this->t('Send Method'),
+      '#description' => $this->t('The method to use for sending sms.'),
+      '#options' => array(
+        $this->t('HTTP GET (Split server request if recipients > 400)'),
+        $this->t('HTTP GET (Use POST if recipients > 500)'),
+        $this->t('HTTP POST'),
+//        $this->t('SMPP (Not yet implemented)'),
+      ),
+      '#default_value' => $config['method'],
+    );
+    $form['ssl'] = array(
+      '#type' => 'checkbox',
+      '#title' => $this->t('Use SSL Encyption'),
+      '#description' => $this->t('Drupal\'s built-in HTTP client only supports SSL on PHP 4.3 compiled with OpenSSL.'),
+      '#default_value' => $config['ssl'],
+    );
+    $form['server'] = array(
+      '#type' => 'textfield',
+      '#title' => $this->t('API Server URL'),
+      '#description' => $this->t('The url for accessing the @label api server.', $t_args),
+      '#size' => 40,
+      '#maxlength' => 255,
+      '#default_value' => $config['server'],
+    );
+    $form['username'] = array(
+      '#type' => 'textfield',
+      '#title' => $this->t('Username'),
+      '#description' => $this->t('The username on the @label account.', $t_args),
+      '#size' => 40,
+      '#maxlength' => 255,
+      '#default_value' => $config['username'],
+    );
+    // @todo should this be a password (masked) text input?????
+    $form['password'] = array(
+      '#type' => 'textfield',
+      '#title' => $this->t('Password'),
+      '#description' => $this->t('The current password on the @label account.', $t_args),
+      '#size' => 30,
+      '#maxlength' => 64,
+      '#default_value' => $config['password'],
+    );
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateConfigurationForm(array &$form, array &$form_state) {
+    if (!$this->test($form_state['values'])) {
+      $error = $this->getError();
+      form_set_error($error['form_element'], t('The settings could not be validated. A gateway error occurred: @error.',
+        array('@error' => $error['description'])));
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitConfigurationForm(array &$form, array &$form_state) {
+    $this->configuration['method'] = $form_state['values']['method'];
+    $this->configuration['ssl'] = $form_state['values']['ssl'];
+    $this->configuration['server'] = $form_state['values']['server'];
+    $this->configuration['username'] = $form_state['values']['username'];
+    $this->configuration['password'] = $form_state['values']['password'];
+  }
+}
diff --git a/src/Gateway/GatewayInterface.php b/src/Gateway/GatewayInterface.php
new file mode 100644
index 0000000..0c841bb
--- /dev/null
+++ b/src/Gateway/GatewayInterface.php
@@ -0,0 +1,201 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\sms\Gateway\GatewayInterface
+ */
+
+namespace Drupal\sms\Gateway;
+
+use Drupal\Component\Plugin\ConfigurablePluginInterface;
+use Drupal\Core\Plugin\PluginFormInterface;
+use Drupal\sms\Message\Message;
+use Drupal\sms\Message\MessageInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Default implementation of sms gateway plugin
+ */
+interface GatewayInterface extends ConfigurablePluginInterface, PluginFormInterface {
+  // Gateway response codes
+  // 0=Unknown, 2xx=Positive, 4xx=Negative(likely client err), 5xx=Negative(likely gateway err)
+  /**
+   * Status Unknown.
+   *
+   * A gateway should return this status to indicate unknown status.
+   */
+  const STATUS_UNKNOWN = 0;
+
+  /**
+   * Status OK.
+   *
+   * A gateway should return this status to indicate message successfully sent.
+   */
+  const STATUS_OK = 200;
+
+  /**
+   * Authentication error.
+   *
+   * A gateway should return this status to indicate authentication error.
+   */
+  const STATUS_ERR_AUTH = 401;
+
+  /**
+   * Invalid Call.
+   *
+   * A gateway should return this status to indicate invalid call attempt.
+   */
+  const STATUS_ERR_INVALID_CALL = 400;
+
+  /**
+   * Gateway endpoint not found.
+   *
+   * A gateway should return this status to indicate gateway endpoint not found.
+   */
+  const STATUS_ERR_NOT_FOUND = 404;
+
+  /**
+   * Message limits exceeded.
+   *
+   * A gateway should return this status to indicate message limits exceeded.
+   */
+  const STATUS_ERR_MSG_LIMITS = 413;
+
+  /**
+   * Routing error.
+   *
+   * A gateway should return this status to indicate message routing error.
+   */
+  const STATUS_ERR_MSG_ROUTING = 502;
+
+  /**
+   * Message queuing error.
+   *
+   * A gateway should return this status to indicate message queuing error.
+   */
+  const STATUS_ERR_MSG_QUEUING = 408;
+
+  /**
+   * Other message error.
+   *
+   * A gateway should return this status to indicate other message error.
+   */
+  const STATUS_ERR_MSG_OTHER = 409;
+
+  /**
+   * Source number or id error.
+   *
+   * A gateway should return this status to indicate sender number or id error.
+   */
+  const STATUS_ERR_SRC_NUMBER = 415;
+
+  /**
+   * Destination number error.
+   *
+   * A gateway should return this status to indicate destination number error.
+   */
+  const STATUS_ERR_DEST_NUMBER = 416;
+
+  /**
+   * Credit error.
+   *
+   * A gateway should return this status to indicate insufficient credit error.
+   */
+  const STATUS_ERR_CREDIT = 402;
+
+  /**
+   * Other error.
+   *
+   * A gateway should return this status to indicate a known error condition but
+   * not mappable to any equivalent above.
+   */
+  const STATUS_ERR_OTHER = 500;
+
+  /**
+   * Use get
+   * Connection methods
+   */
+  const HTTP_GET_SPLIT = 0;
+  const HTTP_GET = 1;
+  const HTTP_POST = 2;
+  const SMPP = 3;
+
+  /**
+   * Sends an sms and invokes the corresponding sms receipt method.
+   *
+   * @param \Drupal\sms\Message\MessageInterface $sms
+   *   The sms to be sent.
+   * @param array $options
+   *   Options to be applied while processing this sms.
+   * @return \Drupal\sms\Message\MessageResultInterface
+   *   The result of the sms messaging operation.
+   */
+  public function send(MessageInterface $sms, array $options);
+
+  /**
+   * Returns the credit balance available on this gateway.
+   *
+   * @return number
+   */
+  public function balance();
+
+  /**
+   * Handles delivery reports and invoke the corresponding sms_receipt method
+   *
+   * @param \Symfony\Component\HttpFoundation\Request
+   *   Request object containing the delivery report in raw format.
+   */
+  public function deliveryReport(Request $request);
+
+  /**
+   * Gets the last error message from the gateway.
+   *
+   * @return array
+   *   An array of values containing the following:
+   *   - code: the error code.
+   *   - message: the error message.
+   */
+  public function getError();
+
+  /**
+   * Gets the machine  name of the gateway.
+   *
+   * @return string
+   */
+  public function getIdentifier();
+
+  /**
+  /**
+   * Gets the readable name of the gateway.
+   *
+   * @return string
+   */
+  public function getName();
+
+  /**
+   * Gets the user-readable translated name of the gateway.
+   *
+   * @return string
+   */
+  public function getLabel();
+
+  /**
+   * Returns a boolean to show if the gateway is configurable.
+   *
+   * @return bool
+   *   TRUE if the form is configurable, FALSE if not.
+   */
+  public function isConfigurable();
+
+  /**
+   * Returns a form to be appended to the send form.
+   *
+   * @param array $form
+   *   The parent form array.
+   * @param array $form_state
+   *   Form state.
+   * @returns array
+   *   The form for additional gateway-specific sending options.
+   */
+  public function sendForm(array &$form, array &$form_state);
+}
\ No newline at end of file
diff --git a/src/Gateway/GatewayManager.php b/src/Gateway/GatewayManager.php
new file mode 100644
index 0000000..bcb9f33
--- /dev/null
+++ b/src/Gateway/GatewayManager.php
@@ -0,0 +1,199 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\sms\Gateway\GatewayManager
+ */
+
+namespace Drupal\sms\Gateway;
+
+use Drupal\Core\Config\ConfigFactory;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Plugin\DefaultPluginManager;
+use Drupal\sms\Gateway\HookGateway;
+
+/**
+ * Manages SMS gateways implemented using AnnotatedClassDiscovery
+ */
+class GatewayManager extends DefaultPluginManager implements GatewayManagerInterface {
+  /**
+   * Configuration factory for this gateway manager.
+   *
+   * @var \Drupal\Core\Config\ConfigFactory
+   */
+  protected $config;
+
+  /**
+   * List of gateways managed by this gateway manager.
+   *
+   * @var \Drupal\sms\Gateway\GatewayInterface[]
+   */
+  protected $gateways;
+
+  /**
+   * List of human-readable names for the gateways.
+   *
+   * @var string[]
+   */
+  protected $names;
+
+  /**
+   * List of the gateways that have been enabled.
+   *
+   * A list of gateway labels is keyed by the gateway ids (names)
+   * @var array
+   */
+  protected $enabledGateways;
+
+  /**
+   * The default gateway.
+   *
+   * @var string
+   */
+  protected $defaultGateway;
+
+  /**
+   * Create new GatewayManager instance.
+   *
+   * @param \Traversable $namespaces
+   *   The namespaces to search for the gateway plugins.
+   * @param \Drupal\Core\Config\ConfigFactory
+   *   Handles the instantiation of gateways based on stored configuration.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface
+   *   Module handler for calling module hooks.
+   */
+  public function __construct(\Traversable $namespaces, ConfigFactory $config, ModuleHandlerInterface $module_handler) {
+    parent::__construct('Plugin/Gateway', $namespaces, $module_handler, 'Drupal\sms\Annotation\SmsGateway');
+//    $this->setCacheBackend($cache_backend, $language_manager, 'mail_backend_plugins');
+    $this->config = $config;
+    $this->enabledGateways = $this->config->get('sms.settings')->get('enabled_gateways');
+    $this->defaultGateway = $this->config->get('sms.settings')->get('default_gateway');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getGateway($gateway_id) {
+    // Ensure gateway list has been built.
+    $gateways = $this->getAvailableGateways();
+    if (!isset($gateways[$gateway_id])) {
+      return null;
+    }
+    else {
+      return $gateways[$gateway_id];
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDefaultGateway() {
+    if (!isset($this->defaultGateway)) {
+      $this->defaultGateway = $this->config->get('sms.settings')
+        ->get('default_gateway');
+    }
+    return $this->getGateway($this->defaultGateway);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setDefaultGateway($gateway_id) {
+    // Cannot make a disabled gateway default.
+    if (!$this->enabledGateways[$gateway_id]) {
+      return;
+    }
+    $this->defaultGateway = $gateway_id;
+
+    $this->config->get('sms.settings')
+      ->set('default_gateway', $this->defaultGateway)
+      ->save();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getAvailableGateways() {
+    if (!isset($this->gateways)) {
+      $this->buildGateways();
+    }
+    return $this->gateways;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getEnabledGateways() {
+    if (!isset($this->enabledGateways)) {
+      $this->enabledGateways = $this->config->get('sms.settings')
+        ->get('enabled_gateways');
+    }
+    if (!isset($this->enabledGateways)) {
+      $this->enabledGateways = array();
+    }
+
+    // Ensure gateway list has been built.
+    $gateways = $this->getAvailableGateways();
+
+    return array_intersect_key($gateways, $this->enabledGateways);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setEnabledGateways(array $gateways) {
+    $gateways = array_intersect($gateways, array_keys($this->getAvailableGateways()));
+    $this->enabledGateways = array_fill_keys($gateways, TRUE);
+    $this->config->get('sms.settings')
+      ->set('enabled_gateways', $this->enabledGateways)
+      ->save();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isGatewayEnabled($gateway_id) {
+    return !empty($this->enabledGateways[$gateway_id]);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function saveConfiguration($gateway) {
+    if (is_string($gateway)) $gateway = $this->getGateway($gateway);
+    $this->config->get('sms.gateway.config')
+      ->set($gateway->getName(), $gateway->getConfiguration())
+      ->save();
+  }
+
+  /**
+   * Builds the gateway plugin objects from the definitions.
+   *
+   * @return array
+   *   \Drupal\sms\Gateway\GatewayInterface[]
+   *
+   * @todo remove BC-shim when all gateways are converted to plugins.
+   */
+  protected function buildGateways() {
+    $definitions = $this->getDefinitions();
+    foreach ($definitions as $id => $definition) {
+      $settings = $this->config->get('sms.gateway.config')->get($id);
+      // Note that DefaultFactory::createInstance will get the right definitions.
+      if (!isset($settings)) $settings = array();
+      $this->gateways[$id] = $this->createInstance($id, $settings);
+      $this->names[$id] = $this->gateways[$id]->getLabel();
+    }
+
+    // BC-shim for gateways still based on hook_gateway_info implementation.
+    $gateway_array = \Drupal::moduleHandler()->invokeAll('gateway_info');
+    foreach ($gateway_array as $id => $info) {
+      $settings = $this->config->get('sms.gateway.config')->get($id);
+      if (!isset($settings)) $settings = array();
+      $this->gateways[$id] = new HookGateway($info, $settings);
+      $this->names[$id] = $this->gateways[$id]->getLabel();
+    }
+
+    // Is this needed??
+    asort($this->names);
+  }
+}
\ No newline at end of file
diff --git a/src/Gateway/GatewayManagerInterface.php b/src/Gateway/GatewayManagerInterface.php
new file mode 100644
index 0000000..af296de
--- /dev/null
+++ b/src/Gateway/GatewayManagerInterface.php
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\sms\GatewayInterface
+ */
+namespace Drupal\sms\Gateway;
+
+/**
+ * Manages SMS Gateways.
+ */
+interface GatewayManagerInterface {
+  /**
+   * Get the list of all discoverable SMS gateways.
+   *
+   * @return \Drupal\sms\Gateway\GatewayInterface[]
+   */
+  public function getAvailableGateways();
+
+  /**
+   * Get the list of all enabled SMS gateways.
+   *
+   * @return \Drupal\sms\Gateway\GatewayInterface[]
+   */
+  public function getEnabledGateways();
+
+  /**
+   * Get the default SMS gateway.
+   *
+   * @return \Drupal\sms\Gateway\GatewayInterface
+   */
+  public function getDefaultGateway();
+
+  /**
+   * Get the gateway whose id is specified
+   *
+   * @param string $gateway_id
+   *   The gateway id.
+   * @return \Drupal\sms\Gateway\GatewayInterface
+   */
+  public function getGateway($gateway_id);
+
+  /**
+   * Sets the list of gateways that are enabled.
+   *
+   * @param array $gateways
+   *   An array of ids of the gateways to be enabled.
+   */
+  public function setEnabledGateways(array $gateways);
+
+  /**
+   * Sets the default sms gateway for messaging.
+   *
+   * @param string $gateway_id
+   *   The gateway id.
+   */
+  public function setDefaultGateway($gateway_id);
+
+  /**
+   * Gets the status of the specified gateway.
+   *
+   * @param string $gateway_id
+   *   The id of the gateway to be checked.
+   * @return bool
+   *   TRUE if the gateway is enabled and FALSE otherwise.
+   */
+  public function isGatewayEnabled($gateway_id);
+
+  /**
+   * Saves the configuration of a gateway.
+   *
+   * @param \Drupal\sms\Gateway\GatewayInterface|string
+   *   The gateway whose configuration is to be saved.
+   */
+  public function saveConfiguration($gateway);
+}
\ No newline at end of file
diff --git a/src/Gateway/HookGateway.php b/src/Gateway/HookGateway.php
new file mode 100644
index 0000000..f9da4d1
--- /dev/null
+++ b/src/Gateway/HookGateway.php
@@ -0,0 +1,178 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\sms\Gateway\HookGateway
+ */
+
+namespace Drupal\sms\Gateway;
+
+use Drupal\Component\Plugin\Discovery\DiscoveryTrait;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\sms\Message\MessageInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * BC-shim class to allow hook_gateway_info() based gateways to still work.
+ */
+class HookGateway implements GatewayInterface {
+
+  use StringTranslationTrait;
+
+  /**
+   * The info that was pulled out from hook implementations.
+   *
+   * @var array
+   */
+  protected $info = array();
+
+  /**
+   * The settings (configuration) that was saved in config.
+   *
+   * @var array
+   */
+  protected $settings = array();
+
+  /**
+   * @param array $info
+   *   The info extracted from hook_gateway_info() for this gateway.
+   * @param array $settings
+   *   The settings stored in config for this gateway.
+   */
+  public function __construct(array $info, array $settings) {
+    $this->info = $info;
+    $this->settings = $settings;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function send(MessageInterface $sms, array $options) {
+    if (is_callable($this->info['send'])) $this->info['send']($sms, $options);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function balance() {
+    return 0;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deliveryReport(Request $request) {
+    return;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getError() {
+    return array();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfiguration() {
+    return $this->settings;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setConfiguration(array $configuration) {
+    $this->settings = $configuration;
+  }
+
+  /**
+   * Returns default configuration for this plugin.
+   *
+   * @return array
+   *   An associative array with the default configuration.
+   */
+  public function defaultConfiguration() {
+    return array(
+      'use_ssl' => FALSE,
+      'send_method' => 'HTTP_POST',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function calculateDependencies() {
+    return array();
+  }
+
+  /**
+   * Gets the machine  name of the gateway.
+   *
+   * @return string
+   */
+  public function getIdentifier() {
+    return $this->info['identifier'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getName() {
+    return $this->info['name'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getLabel() {
+    return $this->getName();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isConfigurable() {
+    return isset($this->info['configure form']) && is_callable($this->info['configure form']);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildConfigurationForm(array $form, array &$form_state) {
+    if (is_callable($this->info['configure form'])) {
+      return $this->info['configure form']($form, $form_state);
+    }
+    else {
+      throw new \RuntimeException($this->t('Configuration form callback not available.'));
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateConfigurationForm(array &$form, array &$form_state) {
+    $function = $this->info['configure form'] . '_validate';
+    if (is_callable($function)) $function($form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitConfigurationForm(array &$form, array &$form_state) {
+    $function = $this->info['configure form'] . '_submit';
+    if (is_callable($function)) $function($form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function sendForm(array &$form, array &$form_state) {
+    if (is_callable($this->info['send form'])) {
+      return $this->info['send form']($form, $form_state);
+    }
+    else {
+      return array();
+    }
+  }
+}
diff --git a/src/Message/Message.php b/src/Message/Message.php
new file mode 100644
index 0000000..edf8c8d
--- /dev/null
+++ b/src/Message/Message.php
@@ -0,0 +1,102 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\sms\Message\Message class
+ */
+
+namespace Drupal\sms\Message;
+
+/**
+ * Basic implementation of an sms message.
+ */
+class Message implements MessageInterface {
+  /**
+   * The unique identifier for this message.
+   *
+   * @var string
+   */
+  protected $uuid;
+
+  /**
+   * The sender of the message.
+   *
+   * @var string
+   */
+  protected $sender;
+
+  /**
+   * @var array
+   *   The recipients of the message.
+   */
+  protected $recipients = array();
+
+  /**
+   * @var string
+   *   The content of the message to be sent.
+   */
+  protected $message;
+
+  /**
+   * @var string
+   *   Other options to be used for the sms.
+   */
+  protected $options = array();
+
+  /**
+   * Create a new instance of an sms message.
+   *
+   * @param string
+   *   The sender of the message.
+   * @param array
+   *   The list of recipient phone numbers for the message.
+   * @param string
+   *   The actual sms message to be sent.
+   * @param array
+   *   Additional options to be considered in building the sms message
+   */
+  public function __construct($sender, array $recipients, $message, array $options) {
+    $this->sender = $sender;
+    $this->recipients = $recipients;
+    $this->message = $message;
+    $this->options = $options;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getSender() {
+    return $this->sender;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMessage() {
+    return $this->message;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRecipients() {
+    return $this->recipients;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getOptions() {
+    return $this->options;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getOption($name) {
+    if (array_key_exists($name, $this->options)) {
+      return $this->options[$name];
+    }
+    return NULL;
+  }
+}
\ No newline at end of file
diff --git a/src/Message/MessageInterface.php b/src/Message/MessageInterface.php
new file mode 100644
index 0000000..86832af
--- /dev/null
+++ b/src/Message/MessageInterface.php
@@ -0,0 +1,102 @@
+<?php
+
+/**
+ * @file
+ * Contains definition of \Drupal\sms\Message\MessageInterface
+ */
+
+namespace Drupal\sms\Message;
+
+/**
+ * Contains information about an sms.
+ */
+interface MessageInterface {
+// Message status codes
+// 0=Unknown, 2xx=Positive, 3xx=Positive/Neutral (context-dependent), 4xx=Negative
+  /**
+   * Status Unknown.
+   *
+   * A message would have this to indicate unknown status.
+   */
+  const STATUS_UNKNOWN = 0;
+
+  /**
+   * Status OK.
+   *
+   * A message with this status indicates it was successfully sent.
+   */
+  const STATUS_OK = 200;
+
+  /**
+   * Status DELIVERED.
+   *
+   * A message with this status indicates it was successfully delivered.
+   */
+  const STATUS_DELIVERED = 202;
+
+  /**
+   * Status QUEUED.
+   *
+   * A message with this status indicates it was successfully queued for sending.
+   */
+  const STATUS_QUEUED = 302;
+
+  /**
+   * Status ERROR.
+   *
+   * A message with this status indicates it could not be sent (routing reasons).
+   */
+  const STATUS_ERROR = 400;
+
+  /**
+   * Status NO_CREDIT.
+   *
+   * A message with this status indicates it could not be sent due to low credit
+   * balance.
+   */
+  const STATUS_NO_CREDIT = 402;
+
+  /**
+   * Status EXPIRED.
+   *
+   * A message with this status indicates it has expired and has not been sent.
+   */
+  const STATUS_EXPIRED = 408;
+
+  /**
+   * Get the list of recipients of this sms message.
+   *
+   * @return array
+   */
+  public function getRecipients();
+
+  /**
+   * Get the options for building or sending this sms message.
+   *
+   * @return array
+   */
+  public function getOptions();
+
+  /**
+   * Get the option specified by the key $name.
+   *
+   * @param string
+   *   The name of the option.
+   * @return array
+   */
+  public function getOption($name);
+
+  /**
+   * Get the name of the sender of this sms message.
+   *
+   * @return string
+   */
+  public function getSender();
+
+  /**
+   * Get the message to be sent.
+   *
+   * @return string
+   */
+  public function getMessage();
+}
\ No newline at end of file
diff --git a/src/Message/MessageResult.php b/src/Message/MessageResult.php
new file mode 100644
index 0000000..5c3dfce
--- /dev/null
+++ b/src/Message/MessageResult.php
@@ -0,0 +1,138 @@
+<?php
+
+/**
+ * Contains \Drupal\sms\Message\MessageResult
+ */
+
+namespace Drupal\sms\Message;
+
+
+/**
+ * The result of an sms messaging transaction.
+ */
+class MessageResult implements MessageResultInterface {
+  /**
+   * The status of the message.
+   *
+   * @var bool
+   */
+  public $status;
+
+  /**
+   * The translated error message if status is FALSE.
+   *
+   * @var string
+   */
+  public $errorMessage;
+
+  /**
+   * The credits used for this message.
+   *
+   * @var integer
+   */
+  public $creditsUsed;
+
+  /**
+   * The credit balance after this message is sent.
+   *
+   * @var integer
+   */
+  public $creditBalance;
+
+  /**
+   * The message reports keyed by recipient number.
+   *
+   * @var array
+   */
+  public $report;
+
+  /**
+   * Create a new message result based on data supplied in the array.
+   *
+   * @param array $data
+   *   Information to be used to instantiate the MessageResult.
+   */
+  public function __construct($data) {
+    $this->status = $data['status'];
+    $this->creditBalance = $data['credit_balance'];
+    $this->creditUsed = $data['credit_used'];
+    $this->errorMessage = $data['error_message'];
+    $this->report = $data['report'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getStatus() {
+    $this->status;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getReport() {
+    $this->report;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getBalance() {
+    $this->creditBalance;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCreditsUsed() {
+    $this->creditsUsed;
+  }
+
+  /**
+   * {@inheritdoc}
+   *
+   * @return array(
+   *     'status'  => TRUE | FALSE,
+   *     'error_message' => '<message to display if status above is FALSE>',
+   *     'credit_used' => '<credits used>',
+   *     'credit_balance' => '<credits remaining>',
+   *     'report'  => array(
+   *       '<number>' => array(
+   *         'status' => TRUE | FALSE   // Essentially TRUE if there is a message id
+   *         'message_id' => '<message id>',
+   *         'error_code' => '<sms framework error code>',
+   *         'error_message'     => '<sms framework error description>',
+   *         'gateway_error_code'     => '<gateway error code>',
+   *         'gateway_error_message'     => '<gateway error message>',
+   *       ),
+   *   );
+   */
+  public function toArray() {
+    return array(
+      'status' => $this->status,
+      'error_message' => $this->errorMessage,
+      'credit_used' => $this->creditUsed,
+      'credit_balance' => $this->creditBalance,
+      'report' => $this->report,
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getErrorMessage() {
+    $this->errorMessage;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getReportFor($recipient) {
+    if (isset($this->report[$recipient])) {
+      $this->report[$recipient];
+    }
+    else {
+      return null;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/Message/MessageResultInterface.php b/src/Message/MessageResultInterface.php
new file mode 100644
index 0000000..9a6e80e
--- /dev/null
+++ b/src/Message/MessageResultInterface.php
@@ -0,0 +1,96 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\sms\Message\MessageResultInterface
+ */
+
+namespace Drupal\sms\Message;
+
+/**
+ * Contains information on message results.
+ * @return array(
+ *     'status'  => TRUE | FALSE,
+ *     'message' => '<message to display if status above is FALSE>',
+ *     'credit used' => '<credits used>',
+ *     'credit balance' => '<credits remaining>',
+ *     'report'  => array(
+ *       '<number>' => array(
+ *         'status' => TRUE | FALSE   // Essentially TRUE if there is a message id
+ *         'error code' => '<error code>',
+ *         'error'     => '<error description>',
+ *         'error map'     => '<sms framework error code>',
+ *         'message id' => '<message id>',
+ *       ),
+ *   );
+ *
+ */
+interface MessageResultInterface {
+  /**
+   * Gets the status of the message.
+   *
+   * @return bool
+   *   True if message was sent without errors. False if message could not be
+   *     sent.
+   */
+  public function getStatus();
+
+  /**
+   * Gets the translated error message.
+   *
+   * @return string
+   *  The translated error message if the status is FALSE.
+   */
+  public function getErrorMessage();
+
+  /**
+   * Gets the report for all recipients.
+   *
+   * @return array
+   *   The report for all recipients. This report is an array keyed by the
+   *   recipients' numbers. The value is also an array with the following keys:
+   *   - status: TRUE if message was successfully sent, FALSE otherwise.
+   *   - message_id: The message id if the message was successfully sent. Other
+   *     wise 0.
+   *   - error_code: The error code number.
+   *   - error_message: The description of the error message.
+   *   - gateway_error_code: The original error code from the sms gateway.
+   *   - gateway_error_message: The original error message from the sms gateway.
+   */
+  public function getReport();
+
+  /**
+   * Gets the credit balance after the sms was sent.
+   *
+   * @return integer
+   *   The value of the balance. This number is in the sms gateway's chosen
+   *   denomination.
+   */
+  public function getBalance();
+
+  /**
+   * Gets the sms credits used for this transaction.
+   *
+   * @return integer
+   *   The value of the sms used in the gateway's chosen denomination.
+   */
+  public function getCreditsUsed();
+
+  /**
+   * Returns this result report as an array.
+   *
+   * @return array
+   */
+  public function toArray();
+
+  /**
+   * Gets the specific report for a particular recipient.
+   *
+   * @param string $recipient
+   *   The number of the recipient for which the report is to be retrieved.
+   * @return array
+   *   An array containing the message report @link see MessageResultInterface::getReport()
+   * @endlink
+   */
+  public function getReportFor($recipient);
+}
\ No newline at end of file
diff --git a/src/Plugin/Gateway/DebugGateway.php b/src/Plugin/Gateway/DebugGateway.php
new file mode 100644
index 0000000..238a119
--- /dev/null
+++ b/src/Plugin/Gateway/DebugGateway.php
@@ -0,0 +1,219 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\sms\Plugin\Gateway\DebugGatewayDefaultImpl
+ */
+
+namespace Drupal\sms\Plugin\Gateway;
+
+use Drupal\sms\Gateway\GatewayDefaultImpl;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * @SmsGateway(
+ *   id = "debug",
+ *   label = @Translation("Debug Gateway"),
+ *   configurable = TRUE,
+ * )
+ */
+class DebugGatewayDefaultImpl extends GatewayDefaultImpl {
+  /**
+   * {@inheritdoc}
+   */
+  public function defaultConfiguration() {
+    return array(
+      'random' => '',
+      'message_failure' => '',
+      'delivery_failure' => '',
+      'retain_dlrs' => '',
+    ) + parent::defaultConfiguration();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getError() {
+    // TODO: Implement getError() method.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function doCommand($command, array $data, array $options = NULL) {
+    $config = $this->getConfiguration();
+    switch ($command) {
+      case 'send':
+        // Log the messages and generate message id's for each sender
+        $report = array();
+        $msgids = '';
+        foreach ($data['recipients'] as $number) {
+          // Coin toss to determine if message 'fails' or 'succeeds'
+          if (rand(0, 100) < $config['message_failure']) { // 'Failed'
+            $err = rand(-13, -1); // Random error message
+            $msgids .= $err . "\n";
+            $report[$number] = array(
+              'status' => FALSE,
+              'message_id' => '',
+              'error_code' => $err,
+              'error_message' => self::$errorCodes[$err],
+            );
+          }
+          else {    // 'Succeeded'
+            $msgid = $this->randomID();
+            $msgids .= $msgid . "\n";
+            $report[$number] = array(
+              'status' => TRUE,
+              'message_id' => $msgid,
+              'error_code' => 0,
+              'error_message' => '',
+            );
+          }
+        }
+        $message = $this->cleanMessage($data['message']);
+        $numbers = implode(',', $data['numbers']);
+        watchdog('sms_debug', "SMS message sent to %number with the text: @message\nmessage ids: @msgids", array('%number' => $numbers, '@message' => $data['message'], '@msgids' => $msgids), WATCHDOG_INFO);
+
+        // Save the msgids for dlr generation
+        $delivery_report = \Drupal::config('sms.debug_gateway.reports')->get('delivery_report');
+        $delivery_report[] = $report;
+        // @todo Optimize this later
+        \Drupal::config('sms.debug_gateway.reports')->set('delivery_report', $delivery_report)->save();
+        return array('status' => TRUE, 'report' => $report);
+
+      case 'report': 	// Delivery report
+        $dlr_config = \Drupal::config('sms.debug_gateway.reports');
+        $reports = array(
+          'status' => TRUE,
+          'data' => $dlr_config->get('delivery_report'),
+        );
+        if (!$config['retain_dlrs']) {
+          $dlr_config->delete('delivery_report')->save();
+        }
+        return $reports;
+
+      case 'credits': case 'test':
+      return array(
+        'status' => TRUE,
+        'credit_balance' => '100000'
+      );
+
+      default:
+        return array(
+          'status' => FALSE,
+          'message' => t('An error occurred during the HTTP request: @error', array('@error' => 'Unknown error'))
+        );
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deliveryReport(Request $request) {
+    return;
+  }
+  
+  /**
+   * {@inheritdoc}
+   */
+  public function buildConfigurationForm(array $form, array &$form_state) {
+    $form['balance'] = array(
+      '#type' => 'item',
+      '#title' => t('Current balance'),
+      '#markup' => $this->balance(),
+    );
+    
+    $config = $this->getConfiguration() + array(
+        'random' => '',
+        'message_failure' => '',
+        'delivery_failure' => '',
+        'retain_dlrs' => '',
+      );
+
+    $form['debug'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Random failure settings'),
+      '#collapsible' => FALSE,
+      '#tree' => TRUE,
+    );
+    $form['debug']['random'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Enable random failures'),
+      '#description' => t('Enable generation of random errors to simulate real world messaging.'),
+      '#default_value' => $config['random'],
+    );
+    $form['debug']['message_failure'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Message failure rate'),
+      '#description' => t('Simulated rate for failure of messages (percentage).'),
+      '#field_suffix' => '%',
+      '#size' => 30,
+      '#maxlength' => 64,
+      '#default_value' => $config['message_failure'],
+    );
+    $form['debug']['delivery_failure'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Message delivery failure rate'),
+      '#description' => t('Simulated rate for failure of delivery reports (percentage).'),
+      '#field_suffix' => '%',
+      '#size' => 30,
+      '#maxlength' => 64,
+      '#default_value' => $config['delivery_failure'],
+    );
+
+    $form['retain_dlrs'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Retain delivery reports after poll'),
+      '#description' => t('Retains delivery reports after they have been polled. <br/>Default behaviour is to delete'),
+      '#default_value' => $config['retain_dlrs'],
+    );
+
+    $form['clear_dlrs'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Clear all delivery reports now'),
+      '#description' => t('Clear all delivery reports and records stored'),
+    );
+
+    return $form;
+  }
+  
+  /**
+   * {@inheritdoc}
+   */
+  public function validateConfigurationForm(array &$form, array &$form_state) {
+    if (!$this->test($form_state['values']['debug'])) {
+      $error = $this->getError();
+      form_set_error('', t('A Debug gateway error occurred: @error.', array('@error' => $error['description'])));
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitConfigurationForm(array &$form, array &$form_state) {
+    $this->configuration = $form_state['values']['debug'];
+    $this->configuration['retain_dlrs'] = $form_state['values']['retain_dlrs'];
+
+    // @todo: Storage for this should be moved to a more appropriate location.
+    if ($form_state['values']['clear_dlrs']) $this->configuration['debug_reports'] = array();
+  }
+
+  /**
+   * Debug error codes
+   */
+  static $errorCodes = array(
+    '-1' => 'SEND_ERROR',
+    '-2' => 'NOT_ENOUGHCREDITS',
+    '-3' => 'NETWORK_NOTCOVERED',
+    '-4' => 'SOCKET_EXCEPTION',
+    '-5' => 'INVALID_USER_OR_PASS',
+    '-6' => 'MISSING_DESTINATION_ADDRESS',
+    '-7' => 'MISSING_SMSTEXT',
+    '-8' => 'MISSING_SENDERNAME',
+    '-9' => 'DESTADDR_INVALIDFORMAT',
+    '-10' => 'MISSING_USERNAME',
+    '-11' => 'MISSING_PASS',
+    '-12' => 'MISSING_WAPURL',
+    '-13' => 'INVALID_DESTINATION_ADDRESS',
+  );
+}
diff --git a/src/Plugin/Gateway/LogGateway.php b/src/Plugin/Gateway/LogGateway.php
new file mode 100644
index 0000000..c37c1f4
--- /dev/null
+++ b/src/Plugin/Gateway/LogGateway.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\sms\Plugin\Gateway\LogGateway
+ */
+
+namespace Drupal\sms\Plugin\Gateway;
+
+use Drupal\sms\Gateway\GatewayBase;
+use Drupal\sms\Message\Message;
+use Drupal\sms\Message\MessageInterface;
+use Drupal\sms\SmsMessage;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * @SmsGateway(
+ *   id = "log",
+ *   label = @Translation("Log only"),
+ *   configurable = FALSE,
+ * )
+ */
+class LogGateway extends GatewayBase {
+  /**
+   * {@inheritdoc}
+   *
+   * Log sms message to drupal watchdog().
+   */
+  public function send(MessageInterface $sms, array $options) {
+    watchdog('sms', 'SMS message sent to %number with the text: @message',
+      array('%number' => implode(', ', $sms->getRecipients()), '@message' => $sms->getMessage()), WATCHDOG_INFO);
+//    return array('status' => TRUE);
+  }
+
+
+  /**
+   * {@inheritdoc}
+   */
+  public function balance() {
+    return 0;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function deliveryReport(Request $request) {
+    return;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getError() {
+    return array();
+  }
+}
diff --git a/src/Sms.php b/src/Sms.php
new file mode 100644
index 0000000..b4c4d9d
--- /dev/null
+++ b/src/Sms.php
@@ -0,0 +1,165 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\sms\Sms
+ */
+
+namespace Drupal\sms;
+
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\sms\Gateway\GatewayInterface;
+use Drupal\sms\Gateway\GatewayManagerInterface;
+use Drupal\sms\Message\MessageInterface;
+use Drupal\sms\SmsException;
+use Drupal\sms\Message\Message;
+
+/**
+ * This is the SMS service that provides messaging functionality
+ */
+class Sms implements SmsProviderInterface {
+  /**
+   * @var \Drupal\sms\Gateway\GatewayManager
+   *
+   * The sms gateway manager.
+   */
+  protected $gatewayManager;
+
+  /**
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   *
+   * The module handler.
+   */
+  protected $moduleHandler;
+
+  /**
+   * Create a new instance of \Drupal\sms\Sms.
+   *
+   * @param \Drupal\sms\Gateway\GatewayManagerInterface
+   *   The sms gateway manager.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface
+   *   The module handler.
+   */
+  public function __construct(GatewayManagerInterface $gateway_manager, ModuleHandlerInterface $module_handler) {
+    $this->gatewayManager = $gateway_manager;
+    $this->moduleHandler = $module_handler;
+  }
+
+  /**
+   * {@inheritdoc}
+   *
+   * @TODO An effective method of cascading messages and errors back up from the
+   *   gateways.
+   */
+  public function send(MessageInterface $sms, array $options = array()) {
+    $gateway = $this->gatewayManager->getDefaultGateway();
+
+    if ($this->preProcess($sms, $options, $gateway)) {
+      $response = NULL;
+      $response = $gateway->send($sms, $options);
+      $result = $this->handleResult($response, $sms);
+
+      $this->postProcess($sms, $options, $gateway, $result);
+      return $result;
+    }
+    else {
+      return FALSE;
+    }
+  }
+
+  /**
+   * Calls pre-process hooks and ensures that the action is still permitted.
+   *
+   * @param \Drupal\sms\Message\MessageInterface $sms
+   *   The sms to be sent.
+   * @param array $options
+   *   Additonal options to be passed to the sms gateway.
+   * @param \Drupal\sms\Gateway\GatewayInterface $gateway
+       The default gateway for sending this message.
+   * @returns bool
+   *   Whether to continue sending or not.
+   */
+  protected function preProcess(MessageInterface $sms, array $options, GatewayInterface $gateway) {
+    // Call the send hook.
+    // @todo change this later to a preprocess or presend hook
+    $continue = TRUE;
+    foreach ($this->moduleHandler->getImplementations('sms_send') as $module) {
+      $function = $module . '_sms_send';
+      $continue &= $function($sms, $options, $gateway);
+    }
+    return $continue;
+  }
+
+  /**
+   * Calls post process hooks.
+   *
+   * @param \Drupal\sms\Message\MessageInterface $sms
+   *   The sms that was sent.
+   * @param array $options
+   *   Additonal options that were passed to the sms gateway.
+   * @param \Drupal\sms\Gateway\GatewayInterface $gateway
+   *   The default gateway for sending this message.
+   * @param bool $result
+   *   Whether the sms sending was successful or not.
+   */
+  protected function postProcess(MessageInterface $sms, array $options, GatewayInterface $gateway, $result) {
+    // Post process hook
+    foreach ($this->moduleHandler->getImplementations('sms_send_process') as $module) {
+      $function = $module . '_sms_send_process';
+      $function('post process', $sms, $options, $gateway, $result);
+    }
+  }
+
+  /**
+   * Handles the response back from the sms gateway.
+   *
+   * @param array
+   *   The result to be handled.
+   * @param \Drupal\sms\Message\MessageInterface
+   *   The message that was sent.
+   * @return bool
+   *   True if message was sent successfully. Throws an SmsException if message
+   *   sending failed.
+   * @throws \Drupal\sms\SmsException
+   *
+   */
+  protected function handleResult($result, MessageInterface $sms) {
+    if ($result['status']) {
+      return TRUE;
+    }
+    else {
+      // @todo Review all of this.
+      $variables['%number'] = implode(',', $sms->getRecipients());
+      if (!empty($result['variables'])) {
+        $variables = array_merge($variables, $result['variables']);
+      }
+      if ($result['message']) {
+        $variables['%message'] = $result['message'];
+        $error_message = t('Sending SMS to %number failed. The gateway said: %message', $variables);
+      }
+      else {
+        $error_message = t('Sending SMS to %number failed.', $variables);
+      }
+      throw new SmsException($error_message);
+//      watchdog('sms', $error_message, $variables, WATCHDOG_ERROR);
+//      return FALSE;
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function incoming(MessageInterface $message, array $options) {
+
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function receipt($number, $reference, $message_status = GatewayInterface::STATUS_UNKNOWN, $options = array()) {
+    // Execute three phases
+    $this->moduleHandler->invokeAll('sms_receipt', array('pre process', $number, $reference, $message_status, $options));
+    $this->moduleHandler->invokeAll('sms_receipt', array('process', $number, $reference, $message_status, $options));
+    $this->moduleHandler->invokeAll('sms_receipt', array('post process', $number, $reference, $message_status, $options));
+  }
+
+}
\ No newline at end of file
diff --git a/src/SmsException.php b/src/SmsException.php
new file mode 100644
index 0000000..c300de2
--- /dev/null
+++ b/src/SmsException.php
@@ -0,0 +1,12 @@
+<?php
+
+/**
+ * Contains \Drupal\sms\SmsException
+ */
+
+namespace Drupal\sms;
+
+/**
+ * Base exception thrown for any sms operations.
+ */
+class SmsException extends \RuntimeException {}
\ No newline at end of file
diff --git a/src/SmsProviderInterface.php b/src/SmsProviderInterface.php
new file mode 100644
index 0000000..646bda1
--- /dev/null
+++ b/src/SmsProviderInterface.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * @file
+ * Contains definition of \Drupal\sms\SmsProviderInterface
+ */
+
+namespace Drupal\sms;
+use Drupal\sms\Message\Message;
+use Drupal\sms\Message\MessageInterface;
+
+/**
+ * Provides an interface for sending messages
+ */
+interface SmsProviderInterface {
+  /**
+   * Sends an sms using the active gateway.
+   *
+   * @param \Drupal\sms\Message\MessageInterface
+   *   The sms to be sent.
+   * @param array
+   *   Additonal options to be passed to the sms gateway.
+   */
+  public function send(MessageInterface $sms, array $options);
+
+  /**
+   * Handles a message received by the server.
+   *
+   * @param \Drupal\sms\Message\MessageInterface
+   *   The message received.
+   * @param array
+   *   Additional options to be passed to the sms gateway.
+   */
+  public function incoming(MessageInterface $sms, array $options);
+
+  /**
+   * Handles responses to .
+   *
+   * Allows gateway modules to pass message receipts in a standard format for
+   * processing, and provides a basic set of status codes for common code handling.
+   *
+   * Allowed message status codes are defined as constants at
+   * {@link} \Drupal\sms\Gateway\GatewayInterface
+   *
+   * The gateway code and string will often be provided in the $options array as
+   * 'gateway_message_status' and 'gateway_message_status_text'.
+   *
+   * @param string $number
+   *   The sender's mobile number.
+   *
+   * @param string $reference
+   *   Unique message reference code, as provided when message is sent.
+   *
+   * @param int $message_status
+   *   An SMS Framework message status code, as per the defined constants.
+   *
+   * @param array $options
+   *   Extended options passed by the receipt receiver.
+   */
+  public function receipt($number, $reference, $message_status = SMS_GW_UNKNOWN_STATUS, $options = array());
+} 
\ No newline at end of file
