diff --git a/og_invite_link.admin.inc b/og_invite_link.admin.inc
index 714f4e5..be487d9 100644
--- a/og_invite_link.admin.inc
+++ b/og_invite_link.admin.inc
@@ -1,6 +1,5 @@
 <?php
 
-
 /**
  * @file
  *  Contains administration pages.
@@ -23,6 +22,26 @@ function og_invite_link_admin() {
     '#default_value' => variable_get('og_invite_link_expiration', 30),
     '#options' => $options,
   );
+  
+  $form['registration'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Site registration'),
+  );
+  $form['registration']['og_invite_link_invite_unregistered'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Invite people without accounts'),
+    '#description' => t('If enabled, invitations are sent for user registration along with a token so that users can accept invitations when registering.'),
+    '#default_value' => variable_get('og_invite_link_invite_unregistered', 0),
+  );
+  // This setting depends on our implementation of hook_menu_alter(),
+  // so we clear the menu cache after submitting the setting sform.
+  $form['registration']['og_invite_link_allow_registration'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Allow user registration with a valid invite even when site-wide user registration is disabled.'),
+    '#description' => t('Anyone with a valid invitation link and email address combination will be able to register for the site regardless of the settings at admin/user/register'),
+    '#default_value' => variable_get('og_invite_link_allow_registration', 0),
+  );
+  $form['#submit'][] = 'menu_cache_clear_all';
   return system_settings_form($form);
 }
 
diff --git a/og_invite_link.install b/og_invite_link.install
index 000b3f8..b7f2cf5 100644
--- a/og_invite_link.install
+++ b/og_invite_link.install
@@ -1,6 +1,5 @@
 <?php
 
-
 /**
  * @file
  *   Install file for og_invite_link module
@@ -24,6 +23,13 @@ function og_invite_link_schema() {
         'unsigned' => TRUE,
         'not null' => TRUE,
       ),
+      'mail' => array(
+        'type' => 'varchar',
+        'length' => 64,
+        'not null' => FALSE,
+        'default' => '',
+        'description' => "The email address of the invited person, if she does not already have an account.",
+      ),
       'group_nid' => array(
         'description' => 'The group node id into which the user has been invited.',
         'type' => 'int',
@@ -92,3 +98,12 @@ function og_invite_link_uninstall() {
   drupal_uninstall_schema('og_invite_link');
 }
 
+/**
+ * Allow an invite link to be associated with an email address so that
+ * unregistered users can be invited to join the site.
+ */
+function og_invite_link_update_6201() {
+  $ret = array();
+  db_add_column($ret, 'og_invite', 'mail', 'varchar(64)', array('not null' => FALSE));
+  return $ret;
+}
diff --git a/og_invite_link.module b/og_invite_link.module
index 993b191..871aeee 100644
--- a/og_invite_link.module
+++ b/og_invite_link.module
@@ -49,6 +49,87 @@ function og_invite_link_menu() {
 function og_invite_link_menu_alter(&$items) {
   // Remove OG's invite page
   unset($items['og/invite/%node']);
+  $items['user/register']['access callback'] = 'og_invite_link_user_register_access';
+}
+
+/**
+ * Implementation of hook_form_FORM_ID_alter().
+ * 
+ * Alter the user registration form
+ */
+function og_invite_link_form_user_register_alter(&$form, &$form_state) {
+  // Detect any invitation links and provide the registering user with the
+  // option to join the applicable groups.
+  if (variable_get('og_invite_link_invite_unregistered', FALSE) && !empty($_GET['og-invite-token'])) {
+    $min_valid_timestamp = $_SERVER['REQUEST_TIME'] - (variable_get('og_invite_link_expiration', 30) * 6400);
+    if (og_invite_link_valid_unregistered_token($_GET['mail'], $_GET['og-invite-token'])) {
+      // Find all groups this email address has been invited to join with
+      // taking into account changes in group privacy settings
+      // and token expirations.
+      $group_nids = array();
+      $tokens = array();
+      $query = "
+        SELECT oi.group_nid, oi.token, oi.moderated, n.title 
+        FROM {og_invite} oi 
+        INNER JOIN {node} n ON n.nid = oi.group_nid 
+        INNER JOIN {og} og ON og.nid = n.nid 
+        WHERE oi.mail = '%s' 
+        AND (og.og_selective != %d OR oi.moderated = 0) 
+        AND oi.timestamp >= %d
+        AND n.status = 1
+      ";
+      $results = db_query($query, $_GET['mail'], OG_CLOSED, $min_valid_timestamp);
+      while ($result = db_fetch_object($results)) {
+        $group_nids[$result->group_nid] = $result->title;
+        $tokens[$result->group_nid] = array('token' => $result->token, 'moderated' => $result->moderated);
+      }
+
+      if (!empty($group_nids)) {
+        $form['account']['mail']['#default_value'] = check_plain($_GET['mail']);
+        $form['og_invite'] = array(
+          '#type' => 'fieldset',
+          '#title' => t('Group invitations'),
+          '#collapsible' => FALSE,
+          '#collapsed' => FALSE,
+        );  
+        $form['og_invite']['og_invite_group_nids'] = array(
+          '#type' => 'checkboxes',
+          '#options' => $group_nids,
+          '#title' => t("Yes, I'd like to join these groups"),
+          '#default_value' => array_keys($group_nids),
+        );
+        $form['og_invite']['og_invites'] = array(
+          '#type' => 'value',
+          '#value' => $tokens,
+        );
+        $form['#submit'][] = 'og_invite_user_register_submit';
+      }
+      else {
+        drupal_set_message(t("This invitation is either invalid or has expired."));
+      }
+    }
+  }
+}
+
+/**
+ * Submit handler for the user registration form
+ */
+function og_invite_user_register_submit(&$form, &$form_state) {
+  $account = $form_state['user'];
+  foreach ($form_state['values']['og_invite_group_nids'] as $group_nid => $join) {
+    if ($join) {
+      $invite = $form_state['values']['og_invites'][$group_nid]; 
+      // Remove any other pending invitations for this user and group.
+      db_query("DELETE FROM {og_invite} WHERE uid = %d AND group_nid = %d AND token <> '%s'", $account->uid, $group_nid, $invite['token']);
+      // Create a group subscription for the user
+      og_save_subscription($group_nid, $account->uid, array('is_active' => $invite['moderated'] ? 0 : 1));
+      // Update the existing invitations to reflect the newly created account
+      // for tracking purposes.
+      // Note, this will invalidate the existing tokens.
+      db_query("UPDATE {og_invite} SET mail = NULL, uid = %d WHERE mail = '%s'", $account->uid, $account->mail);
+      db_query("UPDATE {og_invite} SET accepted_timestamp = %d WHERE token = '%s'", $_SERVER['REQUEST_TIME'], $invite['token']);
+    }
+  }
 }
 
 /**
@@ -153,6 +234,27 @@ function og_invite_link_invite_access($group = NULL, $user = NULL) {
 }
 
 /**
+ * Access callback for /user/register used to allow user registration when
+ * the registering user has an invitation link but site-wide
+ * registration is disabled.
+ */
+function og_invite_link_user_register_access() {
+  if (!user_is_anonymous()) {
+    return FALSE;
+  }
+  if (variable_get('user_register', 1)) {
+    return TRUE;
+  }
+  return (variable_get('og_invite_link_allow_registration', 0) && og_invite_link_valid_unregistered_token($_GET['mail'], $_GET['og-invite-token']));
+}
+/**
+ * Helper function to validate invitation tokens for unregistered users.
+ */
+function og_invite_link_valid_unregistered_token($mail, $token) {
+  return (bool)db_result(db_query("SELECT iid FROM {og_invite} WHERE token = '%s' AND mail = '%s'", $token, $mail));
+}
+
+/**
  * Check if the user has accesss to the join group callback
  *
  * @param object $node
@@ -200,6 +302,13 @@ function og_invite_link_mail($key, &$message, $params) {
         $users[$invitation->sender] = user_load($invitation->sender);
       }
       $sent_by = $users[$invitation->sender];
+      
+      if (!empty($invitation->uid)) {
+        $invite_url = url("group/{$group->nid}/join/{$invitation->uid}/{$invitation->token}", array('absolute' => TRUE));
+      }
+      else {
+        $invite_url = url("user/register", array('absolute' => TRUE, 'query' => "mail={$message['to']}&og-invite-token={$invitation->token}"));
+      }
 
       // Populate the message variables
       $variables = array(
@@ -209,7 +318,7 @@ function og_invite_link_mail($key, &$message, $params) {
         '@body' => $params['additional_message'],
         '@sent-to' => $sent_to->name,
         '@sent-by' => $sent_by->name,
-        '!group_url' => url("group/{$group->nid}/join/{$invitation->uid}/{$invitation->token}", array('absolute' => TRUE)),
+        '!group_url' => $invite_url,
       );
 
       // Set the message subject and body
@@ -280,7 +389,12 @@ function og_invite_link_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  *   A token string
  */
 function og_invite_link_generate_token($invitation) {
-  return md5(md5($invitation->invite_key) . md5($invitation->group_nid . '-' . $invitation->uid . '-' . $invitation->timestamp));
+  if (empty($invitation->uid) && !empty($invitation->mail)) {
+    return md5(md5($invitation->invite_key) . md5($invitation->group_nid . '-' . $invitation->mail . '-' . $invitation->timestamp));
+  }
+  else {
+    return md5(md5($invitation->invite_key) . md5($invitation->group_nid . '-' . $invitation->uid . '-' . $invitation->timestamp));
+  }
 }
 
 /**
@@ -298,7 +412,7 @@ function og_invite_link_send_invite($user, $group, $additional_message = NULL) {
   $account = is_numeric($user) ? user_load($user) : $user;
 
   // Make sure we have a valid user
-  if (!is_object($account) || !$account->uid) {
+  if (!is_object($account) || (!$account->uid && !variable_get('og_invite_link_invite_unregistered', FALSE)) && empty($account->mail) ) {
     return FALSE;
   }
 
@@ -354,6 +468,9 @@ function og_invite_link_create_invitation($account, $group) {
   $invitation->invite_key = user_password();
   // Generate the token
   $invitation->token = og_invite_link_generate_token($invitation);
+  if (empty($account->uid)) {
+    $invitation->mail = $account->mail;
+  }
   // If the user sending the invite is the group admin
   // the invite is not moderated, meaning the invitee will
   // automatically be accepted regardless of the group type
@@ -522,7 +639,7 @@ function og_invite_link_invite_users_action_submit($form, &$form_state) {
  *   An associative array that contains the following keys:
  *   - groups: An array with organic group nodes.
  *   - invitees: A comma separated string containing the names
- *               of the users to invite
+ *               or email addresses of the users to invite
  *   - additional_message: An additional message to be appended
  *                         to the invitation message.
  *
@@ -555,16 +672,48 @@ function og_invite_link_invite_users_to_groups($params) {
       $name = trim(filter_xss(strip_tags($name)));
 
       // Make sure we have a name to invite after the filtering
-      if ($name == '') {
+      if (strlen($name) == 0) {
         continue;
       }
 
-      // Attempt to load the user and make sure he is a valid one
-      $account = user_load(array('name' => $name));
-      if (!$account->status) {
-        $invalid[] = check_plain($name);
-        continue;
+      // Attempt to load the user
+      if (valid_email_address($name)) {
+        // Load based on email address
+        $account = user_load(array('mail' => $name));
+      }
+      else {
+        // Load based on user name
+        $account = user_load(array('name' => $name));  
+      }
+      
+      // Check if we have a valid user object
+      if (is_object($account)) {
+        // Invalid if the user is inactive
+        if (!$account->status) {
+          $invalid[] = $name;
+          continue; 
+        }
       }
+      // Check if we are allowed to invite non-users
+      else if (variable_get('og_invite_link_invite_unregistered', 0)) {
+        // Make sure we have a valid, non-banned email address
+        if (valid_email_address($name) && !drupal_is_denied('mail', $name)) {
+          // Build a user object
+          $account = new stdClass;
+          $account->uid = 0;
+          $account->mail = $name;
+        }
+        else {
+          $invalid[] = $name;
+          continue; 
+        }
+      }
+      // We have nothing valid
+      else {
+        $invalid[] = $name;
+        continue; 
+      }
+      
       foreach ($params['groups'] as $key => $group) {
         if (!is_array($invitees[$group->nid])) {
           $invitees[$group->nid] = array();
@@ -584,7 +733,13 @@ function og_invite_link_invite_users_to_groups($params) {
         else {
           // Invite the user
           og_invite_link_send_invite($account, $group, $message);
-          $invitees[$group->nid][$account->uid] = theme('username', $account);
+          if ($account->uid) {
+            $invitees[$group->nid][$account->uid] = theme('username', $account);  
+          }
+          else {
+            $invitees[$group->nid][$account->mail] = $account->mail; 
+          }
+          
         }
       }
     }
diff --git a/og_invite_link.pages.inc b/og_invite_link.pages.inc
index f5c5d5f..f31bf3a 100644
--- a/og_invite_link.pages.inc
+++ b/og_invite_link.pages.inc
@@ -1,6 +1,5 @@
 <?php
 
-
 /**
  * @file
  *   Contains the page callback functions for this module
@@ -29,7 +28,7 @@ function og_invite_link_invite_page_form($form_state = array(), $nodes) {
     '#maxlength' => 1024,
     '#required' => TRUE,
     '#autocomplete_path' => 'og_invite_link/autocomplete',
-    '#description' => t('Add one or more usernames in order to invite users in this group. Multiple usernames should be separated by a comma. A maximum of !max invites can be sent out at a time.', array('!max' => OG_INVITE_LINK_MAX_INVITES_PER_FORM)),
+    '#description' => t('Add one or more usernames or email addresses in order to invite users in this group. Multiple usernames should be separated by a comma. A maximum of !max invites can be sent out at a time.', array('!max' => OG_INVITE_LINK_MAX_INVITES_PER_FORM)),
   );
   $form['additional_message'] = array(
     '#type' => 'textarea',
@@ -76,7 +75,8 @@ function og_invite_link_invite_page_form_submit($form, &$form_state) {
       'groups' => $form_state['values']['groups'],
       'invitees' => $form_state['values']['invitees'],
       'additional_message' => $form_state['values']['additional_message'],
-    ));
+    )
+  );
   // Here we should not have more than one group.
   $group = current($form_state['values']['groups']);
   // Set a message for the invited users
@@ -91,7 +91,7 @@ function og_invite_link_invite_page_form_submit($form, &$form_state) {
 
   // Set a message for the invalid invitees
   if (!empty($invitiation_result['invalid'])) {
-    drupal_set_message(t('The following invitees are not users: !users', array('!users' => implode(', ', $invitiation_result['invalid']))), 'error');
+    drupal_set_message(t('The following invitees are either not users, or are invalid email addresses: !users', array('!users' => implode(', ', $invitiation_result['invalid']))), 'error');
   }
 }
 
