diff --git a/search_api_saved_searches.module b/search_api_saved_searches.module
index b9ac346..da7b289 100644
--- a/search_api_saved_searches.module
+++ b/search_api_saved_searches.module
@@ -355,6 +355,32 @@ function search_api_saved_searches_user_update(&$edit, $account, $category) {
 }
 
 /**
+ * Retrieves the saved searches that need to be executed.
+ *
+ * @param int|null $settings_id
+ *   (optional) The ID of the saved search settings entity for which to retrieve
+ *   searches. NULL to retrieve for all.
+ *
+ * @return int[]
+ *   The IDs of all searches that need to be executed.
+ */
+function search_api_saved_searches_get_searches_to_be_executed($settings_id = NULL) {
+  // Get all searches whose last execution lies more than the notify_interval
+  // in the past. Add a small amount to the current time, so small differences
+  // in execution time don't result in a delay until the next cron run.
+  $select = db_select('search_api_saved_search', 's');
+  $select->fields('s', array('id'))
+    ->condition('enabled', 1)
+    ->condition('notify_interval', 0, '>=')
+    ->where('last_execute >= last_queued')
+    ->where('last_queued + notify_interval < :time', array(':time' => REQUEST_TIME + 15));
+  if ($settings_id !== NULL) {
+    $select->condition('settings_id', $settings_id);
+  }
+  return $select->execute()->fetchCol();
+}
+
+/**
  * Implements hook_user_delete().
  *
  * If a user is deleted, delete their saved searches, too.
@@ -363,8 +389,6 @@ function search_api_saved_searches_user_delete($account) {
   entity_delete_multiple('search_api_saved_search', array_keys(search_api_saved_search_load_multiple(FALSE, array('uid' => $account->uid))));
 }
 
-// @todo Rules integration
-
 /**
  * Implements hook_search_api_index_update().
  *
@@ -1172,17 +1196,7 @@ function search_api_saved_searches_mail($key, array &$message, array $params) {
  * Queue the saved searches that should be checked for new items.
  */
 function search_api_saved_searches_cron() {
-  // Get all searches whose last execution lies more than the notify_interval
-  // in the past. Add a small amount to the current time, so small differences
-  // in execution time don't result in a delay until the next cron run.
-  $ids = db_select('search_api_saved_search', 's')
-    ->fields('s', array('id'))
-    ->condition('enabled', 1)
-    ->condition('notify_interval', 0, '>=')
-    ->where('last_execute >= last_queued')
-    ->where('last_queued + notify_interval < :time', array(':time' => REQUEST_TIME + 15))
-    ->execute()
-    ->fetchCol();
+  $ids = search_api_saved_searches_get_searches_to_be_executed();
   if (!$ids) {
     return;
   }
@@ -1260,71 +1274,7 @@ function search_api_saved_searches_check_updates(array $search_ids) {
   $index = $settings->index();
   $mail_params = array();
   foreach ($searches as $search) {
-    try {
-      // Make sure we run the query as the user who owns the saved search.
-      // Otherwise node access will not work properly.
-      $search->query['options']['search_api_access_account'] = $search->uid;
-      // Get actual results for the query.
-      $query = $search->query();
-
-      // If a date field is set, use that to filter results.
-      if (!empty($settings->options['date_field'])) {
-        $query->condition($settings->options['date_field'], $search->last_execute, '>');
-      }
-      $response = $query->execute();
-      if (!empty($response['results'])) {
-        $old = array();
-        $new = $results = drupal_map_assoc(array_keys($response['results']));
-        if (empty($settings->options['date_field'])) {
-          // ID-based method: Compare these results to the old ones.
-          $old = drupal_map_assoc(explode(',', $search->results));
-          $new = array_diff_key($results, $old);
-        }
-        if ($new) {
-          // We have new results: send them to the user.
-          // Only load those items that will be sent.
-          $sent_new = $new;
-          if (!empty($settings->options['mail']['notify']['max_results'])) {
-            $sent_new = array_slice($new, 0, $settings->options['mail']['notify']['max_results']);
-          }
-          $sent_new = $index->loadItems($sent_new);
-          $new_results = $sent_new + $new;
-          // Let other modules alter these results.
-          drupal_alter('search_api_saved_searches_new_results', $new_results, $search);
-          if ($new_results) {
-            // We have to slice again in case some items were moved around or
-            // removed by alter hooks.
-            $sent_new = $new_results;
-            if (!empty($settings->options['mail']['notify']['max_results'])) {
-              $sent_new = array_slice($new_results, 0, $settings->options['mail']['notify']['max_results']);
-              // Now some of the top results might still be unloaded.
-              if ($unloaded = array_filter($sent_new, 'is_scalar')) {
-                $sent_new = $index->loadItems($unloaded) + $sent_new;
-              }
-            }
-            $num_results = count($new_results);
-            $mail_params['searches'][] = array(
-              'search' => $search,
-              'num_results' => $num_results,
-              'results' => $sent_new,
-            );
-          }
-        }
-        if (empty($settings->options['date_field']) && ($new || array_diff($old, $results))) {
-          // The results changed in some way: store the latest version.
-          $search->results = implode(',', $results);
-        }
-      }
-      // Use time() instead of REQUEST_TIME to minimize the potential of sending
-      // duplicate results due to longer-running cron queue workers.
-      $search->last_execute = time();
-      $search->save();
-    }
-    catch (SearchApiException $e) {
-      $args = _drupal_decode_exception($e);
-      $args['@id'] = $search->id;
-      throw new SearchApiException(t('%type while trying to check for new results on saved search @id: !message in %function (line %line of %file).', $args));
-    }
+    $mail_params['searches'][] = search_api_saved_search_fetch_search_results($search);
   }
   // If we set any searches in the mail parameters, send the mail.
   if ($mail_params) {
@@ -1338,3 +1288,87 @@ function search_api_saved_searches_check_updates(array $search_ids) {
     }
   }
 }
+
+/**
+ * Fetches the results for a given search object.
+ *
+ * @param object $search
+ *   The search object to check if there are new result.
+ *
+ * @throws SearchApiException
+ *   If an error occurred in one of the searches.
+ */
+function search_api_saved_search_fetch_search_results($search) {
+  $return = array(
+    'result_count' => 0,
+    'results' => array(),
+  );
+
+  if (empty($search_id)) {
+    return $return;
+  }
+  
+  $settings = $search->settings();
+  try {
+    // Make sure we run the query as the user who owns the saved search.
+    // Otherwise node access will not work properly.
+    $search->query['options']['search_api_access_account'] = $search->uid;
+    // Get actual results for the query.
+    $query = $search->query();
+
+    // If a date field is set, use that to filter results.
+    if (!empty($settings->options['date_field'])) {
+      $query->condition($settings->options['date_field'], $search->last_execute, '>');
+    }
+
+    $response = $query->execute();
+    if (!empty($response['results'])) {
+      $old = array();
+      $new = $results = drupal_map_assoc(array_keys($response['results']));
+      if (empty($settings->options['date_field'])) {
+        // ID-based method: Compare these results to the old ones.
+        $old = drupal_map_assoc(explode(',', $search->results));
+        $new = array_diff_key($results, $old);
+      }
+      if ($new) {
+        // We have new results: send them to the user.
+        // Only load those items that will be sent.
+        $sent_new = $new;
+        if (!empty($settings->options['mail']['notify']['max_results'])) {
+          $sent_new = array_slice($new, 0, $settings->options['mail']['notify']['max_results']);
+        }
+
+        $new_results = $sent_new + $new;
+        // Let other modules alter these results.
+        drupal_alter('search_api_saved_searches_new_results', $new_results, $search);
+        if ($new_results) {
+          // We have to slice again in case some items were moved around or
+          // removed by alter hooks.
+          $sent_new = $new_results;
+          if (!empty($settings->options['mail']['notify']['max_results'])) {
+            $sent_new = array_slice($new_results, 0, $settings->options['mail']['notify']['max_results']);
+          }
+          $num_results = count($new_results);
+          $return['search'] = $search;
+          $return['result_count'] = $num_results;
+          $return['results'] = $sent_new;
+
+        }
+      }
+      if (empty($settings->options['date_field']) && ($new || array_diff($old, $results))) {
+        // The results changed in some way: store the latest version.
+        $search->results = implode(',', $results);
+      }
+    }
+    // Use time() instead of REQUEST_TIME to minimize the potential of sending
+    // duplicate results due to longer-running cron queue workers.
+    $search->last_execute = time();
+    $search->save();
+  }
+  catch (SearchApiException $e) {
+    $args = _drupal_decode_exception($e);
+    $args['@id'] = $search->id;
+    throw new SearchApiException(t('%type while trying to check for new results on saved search @id: !message in %function (line %line of %file).', $args));
+  }
+  return $return;
+}
\ No newline at end of file
diff --git a/search_api_saved_searches.rules.inc b/search_api_saved_searches.rules.inc
index e69de29..313ef20 100644
--- a/search_api_saved_searches.rules.inc
+++ b/search_api_saved_searches.rules.inc
@@ -0,0 +1,114 @@
+<?php
+/**
+ * @file
+ * Rules integration file.
+ */
+
+/**
+ * Implements hook_rules_action_info().
+ */
+function search_api_saved_searches_rules_action_info() {
+   return array(
+    'search_api_saved_searches_rules_index_results' => array(
+      'label' => t('Fetch the saved searches'),
+      'parameter' => array(
+        'index_id' => array(
+          'type' => 'integer',
+          'label' => t('Index for which to retrieve searches'),
+          'description' => t('Select the search index for which saved searches should be retrieved.'),
+          'options list' => '_search_api_saved_searches_settings_options_list',
+        ),
+      ),
+      'provides' => array(
+        'search_api_saved_search' => array(
+          'type' => 'list<integer>',
+          'label' => t('List of the IDs of the saved searches that require executing.'),
+        ),
+      ),
+      'group' => t('Search API Saved Searches'),
+    ),
+    'search_api_saved_searches_rules_get_saved_search_new_items' => array(
+      'label' => t('Fetch the new results for a saved search'),
+      'parameter' => array(
+        'index_id' => array(
+          'type' => 'integer',
+          'label' => t('Saved search ID'),
+          'description' => t('The ID of the saved search for which to retrieve new results.'),
+        ),
+      ),
+      'provides' => array(
+        'result_count' => array(
+          'type' => 'integer',
+          'label' => t('The count of results that were found.'),
+        ),
+        'results' => array(
+          'type' => 'list<integer>',
+          'label' => t('The list of new results for the saved search since it was last executed.'),
+        ),
+      ),
+      'group' => t('Search API Saved Searches'),
+    ),
+  );
+}
+
+/**
+ * Callback: Implements the "Fetch the saved searches" rules action.
+ *
+ * @param int|null $settings_id
+ *   (optional) The ID of the saved search settings entity for which to retrieve
+ *   searches. NULL to retrieve for all.
+ *
+ * @return array
+ *   An associative array with key "search_api_saved_search" containing the IDs
+ *   of all searches that should be executed.
+ */
+function search_api_saved_searches_rules_index_results($settings_id) {
+  return array(
+    'search_api_saved_search' => search_api_saved_searches_get_searches_to_be_executed($settings_id),
+  );
+}
+
+
+
+/**
+ * Worker function to check if there are any new saved search results.
+ * 
+ * @param int $search_id
+ *   The ID of the saved searcg setting entity.
+ * 
+ * @return array 
+ *   Array of the results count and the results list for the given search id.
+ */
+function search_api_saved_searches_rules_get_saved_search_new_items($search_id) {
+  $search = search_api_saved_search_load($search_id);
+  $search_result = search_api_saved_search_fetch_search_results($search);
+  return array(
+    'result_count' => $search_result['result_count'],
+    'results' => $search_result['results'],
+  );
+}
+
+
+/**
+ * Retrieves the options list for selecting a saved search settings entity.
+ *
+ * @return string[]
+ *   An associative array mapping saved search settings IDs to index names.
+ */
+function _search_api_saved_searches_settings_options_list() {
+  // Fetch the list of saved searches setting and make a list of values.
+  $entities = entity_load('search_api_saved_searches_settings');
+  $ids = array();
+  foreach ($entities as $entity) {
+    $ids[$entity->index_id][] = $entity->id;
+  }
+
+  $indexes = search_api_index_load_multiple(array_keys($ids));
+  $options = array();
+  foreach ($indexes as $index_id => $index) {
+    foreach ($ids[$index_id] as $settings_id) {
+      $options[$settings_id] = $index->label();
+    }
+  }
+  return $options;
+}
