diff --git a/includes/simplenews.subscription.inc b/includes/simplenews.subscription.inc
index 21867e1..5bd3612 100644
--- a/includes/simplenews.subscription.inc
+++ b/includes/simplenews.subscription.inc
@@ -204,10 +204,31 @@ function simplenews_block_form_submit($form, &$form_state) {
  * @see simplenews_subscriptions_page_form_validate()
  * @see simplenews_subscriptions_page_form_submit()
  */
-function simplenews_subscriptions_page_form($form, &$form_state) {
+function simplenews_subscriptions_page_form($form, &$form_state, $code = NULL) {
   global $user;
 
-  $subscriber = !empty($user->mail) ? simplenews_subscriber_load_by_mail($user->mail) : FALSE;
+  $subscriber = $mail = FALSE;
+  if (!empty($user->mail)) {
+    $subscriber = simplenews_subscriber_load_by_mail($user->mail);
+    $mail = $user->mail;
+  }
+  // If a hash is provided, try to load the corresponding subscriber.
+  else if ($code) {
+    $md5 = drupal_substr($code, 0, 10);
+    list($snid, $tid) = explode('t', drupal_substr($code, 10));
+
+    $subscriber = simplenews_subscriber_load($snid);
+    if (!$subscriber) {
+      drupal_not_found();
+      return;
+    }
+
+    // Check the hash if the comparison fails, return a not found error.
+    if ($md5 != drupal_substr(md5($subscriber->mail . simplenews_private_key()), 0, 10)) {
+      return drupal_not_found();
+    }
+    $mail = $subscriber->mail;
+  }
 
   $form = array();
   $options = array();
@@ -234,12 +255,14 @@ function simplenews_subscriptions_page_form($form, &$form_state) {
     '#default_value' => $default_value
   );
 
-  // If current user is logged in, just display email.
-  // Anonymous users see an email box and will receive confirmations
-  if (user_is_logged_in()) {
-    $form['subscriptions']['#title'] = t('Subscriptions for %mail', array('%mail' => $user->mail));
+  // If we have a mail address, which is either from a logged in user or a
+  // subscriber identified through the hash code, display the mail address
+  // instead of a textfield. Anonymous uses will still have to confirm any
+  // changes.
+  if ($mail) {
+    $form['subscriptions']['#title'] = t('Subscriptions for %mail', array('%mail' => $mail));
     $form['subscriptions']['#description'] = t('Check the newsletters you want to subscribe to. Uncheck the ones you want to unsubscribe from.');
-    $form['subscriptions']['mail'] = array('#type' => 'value', '#value' => $user->mail);
+    $form['subscriptions']['mail'] = array('#type' => 'value', '#value' => $mail);
     $form['update'] = array(
       '#type' => 'submit',
       '#value' => t('Update'),
@@ -288,8 +311,8 @@ function simplenews_subscriptions_page_form_validate($form, &$form_state) {
   }
 
   $checked_newsletters = array_filter($form_state['values']['newsletters']);
-  // Anonymous users must select at least one newsletter.
-  if (!count($checked_newsletters) && !$GLOBALS['user']->uid) {
+  // Unless we're in update mode, at least one checkbox must be checked.
+  if (!count($checked_newsletters) && $form_state['values']['op'] != t('Update')) {
     form_set_error('newsletters', t('You must select at least one newsletter.'));
   }
 }
@@ -306,15 +329,23 @@ function simplenews_subscriptions_page_form_submit($form, &$form_state) {
       // We first subscribe, then unsubscribe. This prevents deletion of subscriptions
       // when unsubscribed from the
       arsort($form_state['values']['newsletters'], SORT_NUMERIC);
+      $confirm_any = FALSE;
       foreach ($form_state['values']['newsletters'] as $tid => $checked) {
+        $confirm = simplenews_require_double_opt_in($tid, $account);
+        $confirm_any |= $confirm;
         if ($checked) {
-          simplenews_subscribe_user($account->mail, $tid, FALSE, 'website');
+          simplenews_subscribe_user($mail, $tid, $confirm, 'website');
         }
         else {
-          simplenews_unsubscribe_user($mail, $tid, FALSE, 'website');
+          simplenews_unsubscribe_user($mail, $tid, $confirm, 'website');
         }
       }
-      drupal_set_message(t('The newsletter subscriptions for %mail have been updated.', array('%mail' => $form_state['values']['mail'])));
+      if ($confirm_any) {
+        drupal_set_message(t('You will receive a confirmation e-mail shortly containing further instructions on how to complete your subscription.'));
+      }
+      else {
+        drupal_set_message(t('The newsletter subscriptions for %mail have been updated.', array('%mail' => $form_state['values']['mail'])));
+      }
       break;
     case t('Subscribe'):
       $confirm_any = FALSE;
diff --git a/simplenews.module b/simplenews.module
index 476bd22..7c3e55b 100644
--- a/simplenews.module
+++ b/simplenews.module
@@ -2081,6 +2081,10 @@ function simplenews_tokens($type, $tokens, $data = array(), $options = array())
             $replacements[$original] = url('newsletter/confirm/remove/' . $hash, array('absolute' => TRUE, 'language' => $language));
             break;
 
+          case 'manage-url':
+            $replacements[$original] = url('newsletter/subscriptions/' . $hash, array('absolute' => TRUE, 'language' => $language));
+            break;
+
           case 'mail':
             $replacements[$original] = $sanitize ? check_plain($subscriber->mail) : $subscriber->mail;
             break;
diff --git a/tests/simplenews.test b/tests/simplenews.test
index 30f0004..7402937 100644
--- a/tests/simplenews.test
+++ b/tests/simplenews.test
@@ -375,6 +375,45 @@ class SimplenewsSubscribeTestCase extends SimplenewsTestCase {
     $this->drupalPost($confirm_url, NULL, t('Unsubscribe'));
     $this->assertRaw(t('%user was unsubscribed from the %newsletter mailing list.', array('%user' => $mail, '%newsletter' => $newsletter->name)), t('Anonymous subscriber remved from newsletter'));
 
+    // Visit the newsletter/subscriptions page with the hash.
+    $subscriber = simplenews_subscriber_load_by_mail($mail);
+
+    $hash = simplenews_generate_hash($subscriber->mail, $subscriber->snid, $tid);
+    $this->drupalGet('newsletter/subscriptions/' . $hash);
+    $this->assertText(t('Subscriptions for @mail', array('@mail' => $mail)));
+
+    $edit = array(
+      'newsletters[' . $tid . ']' => TRUE,
+    );
+    $this->drupalPost(NULL, $edit, t('Update'));
+
+    // Make sure the user is not yet subscribed.
+    $subscriber = simplenews_subscriber_load_by_mail($mail);
+
+    $this->assertTrue(empty($subscriber->tids));
+    $this->assertEqual(SIMPLENEWS_SUBSCRIPTION_STATUS_UNCONFIRMED, $subscriber->newsletter_subscription[$tid]->status);
+
+    $mails = $this->drupalGetMails();
+    $body = $mails[5]['body'];
+    $pattern = '@newsletter/confirm/add/[0-9,a-f]+t[0-9]+@';
+    $found = preg_match($pattern, $body, $match);
+    $confirm_url = $match[0];
+    $this->assertTrue($found, t('Confirmation URL found: @url', array('@url' => $confirm_url)));
+
+    $this->drupalGet($confirm_url);
+    $newsletter = taxonomy_term_load($tid);
+    $this->assertRaw(t('Are you sure you want to add %user to the %newsletter mailing list?', array('%user' => $mail, '%newsletter' => $newsletter->name)), t('Subscription confirmation found.'));
+
+    $this->drupalPost($confirm_url, NULL, t('Subscribe'));
+    $this->assertRaw(t('%user was added to the %newsletter mailing list.', array('%user' => $mail, '%newsletter' => $newsletter->name)), t('Anonymous subscriber added to newsletter'));
+
+    // Make sure the subscription is confirmed now.
+    $subscriber = simplenews_subscriber_load_by_mail($mail);
+
+    $this->assertTrue(isset($subscriber->tids[$tid]));
+    $this->assertEqual(SIMPLENEWS_SUBSCRIPTION_STATUS_SUBSCRIBED, $subscriber->newsletter_subscription[$tid]->status);
+
+
   }
 
 
@@ -1167,7 +1206,7 @@ class SimpleNewsI18nTestCase extends SimplenewsTestCase {
     }
   }
 
-  function dtestCategoryTranslation() {
+  function testCategoryTranslation() {
     $this->drupalLogin($this->admin_user);
     // Make Input Format "Filtered Text" translatable
     $edit = array(
