diff --git a/core/modules/contact/contact.views.inc b/core/modules/contact/contact.views.inc
new file mode 100644
index 0000000..6795b0e
--- /dev/null
+++ b/core/modules/contact/contact.views.inc
@@ -0,0 +1,21 @@
+<?php
+
+/**
+ * @file
+ * Provide views data for contact.module.
+ *
+ * @ingroup views_module_handlers
+ */
+
+/**
+ * Implements hook_views_data_alter().
+ */
+function contact_views_data_alter(&$data) {
+  $data['users']['contact'] = array(
+    'field' => array(
+      'title' => t('Contact link'),
+      'help' => t('Provide a simple link to the user contact page.'),
+      'id' => 'contact_link',
+    ),
+  );
+}
diff --git a/core/modules/contact/lib/Drupal/contact/Plugin/views/field/ContactLink.php b/core/modules/contact/lib/Drupal/contact/Plugin/views/field/ContactLink.php
new file mode 100644
index 0000000..475a72a
--- /dev/null
+++ b/core/modules/contact/lib/Drupal/contact/Plugin/views/field/ContactLink.php
@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\contact\Plugin\views\field\ContactLink.
+ */
+
+namespace Drupal\contact\Plugin\views\field;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Component\Annotation\PluginID;
+use Drupal\user\Plugin\views\field\Link;
+
+/**
+ * Defines a field that links to the user contact page, if access is permitted.
+ *
+ * @ingroup views_field_handlers
+ *
+ * @PluginID("contact_link")
+ */
+class ContactLink extends Link {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildOptionsForm(&$form, &$form_state) {
+    parent::buildOptionsForm($form, $form_state);
+    $form['text']['#title'] = t('Link label');
+    $form['text']['#required'] = TRUE;
+    $form['text']['#default_value'] = empty($this->options['text']) ? t('contact') : $this->options['text'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function access() {
+    // The access logic is implemented per row.
+    return TRUE;
+  }
+
+
+  /**
+   * {@inheritdoc}
+   */
+  public function render_link(EntityInterface $entity, \stdClass $values) {
+
+    if (empty($entity)) {
+      return;
+    }
+
+    // Check access when we pull up the user account so we know
+    // if the user has made the contact page available.
+    $uid = $entity->id();
+
+    $path = "user/$uid/contact";
+    if (!_contact_personal_tab_access($entity->getBCEntity())) {
+      return;
+    }
+
+    $this->options['alter']['make_link'] = TRUE;
+    $this->options['alter']['path'] = $path;
+
+    $title = t('Contact %user', array('%user' => $entity->name->value));
+    $this->options['alter']['attributes'] = array('title' => $title);
+
+    if (!empty($this->options['text'])) {
+      return $this->options['text'];
+    }
+    else {
+      return $title;
+    }
+  }
+
+}
diff --git a/core/modules/contact/lib/Drupal/contact/Tests/Views/ContactLinkTest.php b/core/modules/contact/lib/Drupal/contact/Tests/Views/ContactLinkTest.php
new file mode 100644
index 0000000..c2f6a21
--- /dev/null
+++ b/core/modules/contact/lib/Drupal/contact/Tests/Views/ContactLinkTest.php
@@ -0,0 +1,118 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\contact\Tests\Views\ContactLinkTest.
+ */
+
+namespace Drupal\contact\Tests\Views;
+
+use Drupal\views\Tests\ViewTestBase;
+use Drupal\views\Tests\ViewTestData;
+
+/**
+ * Tests the contact link field.
+ *
+ * @see \Drupal\contact\Plugin\views\field\ContactLink.
+ */
+class ContactLinkTest extends ViewTestBase {
+
+  /**
+   * Stores the user data service used by the test.
+   *
+   * @var \Drupal\user\UserDataInterface
+   */
+  public $userData;
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('contact_test_views');
+
+  /**
+   * Views used by this test.
+   *
+   * @var array
+   */
+  public static $testViews = array('test_contact_link');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Contact: Link Field',
+      'description' => 'Tests the contact link field.',
+      'group' => 'Views module integration',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    ViewTestData::importTestViews(get_class($this), array('contact_test_views'));
+
+    $this->userData = $this->container->get('user.data');
+  }
+
+  /**
+   * Tests contact link.
+   */
+  public function testContactLink() {
+    $accounts = array();
+    $accounts['root'] = user_load(1);
+    // Create an account with access to all contact pages.
+    $admin_account = $this->drupalCreateUser(array('administer users'));
+    $accounts['admin'] = $admin_account;
+    // Create an account with no access to contact pages.
+    $no_contact_account = $this->drupalCreateUser();
+    $accounts['no_contact'] = $no_contact_account;
+
+    // Create an account with access to contact pages.
+    $contact_account = $this->drupalCreateUser(array('access user contact forms'));
+    $accounts['contact'] = $contact_account;
+
+    $this->drupalLogin($admin_account);
+    $this->drupalGet('test-contact-link');
+    // The admin user has access to all contact links beside his own.
+    $this->assertContactLinks($accounts, array('root', 'no_contact', 'contact'));
+
+    $this->drupalLogin($no_contact_account);
+    $this->drupalGet('test-contact-link');
+    // Ensure that the user without the permission doesn't see any link.
+    $this->assertContactLinks($accounts, array());
+
+    $this->drupalLogin($contact_account);
+    $this->drupalGet('test-contact-link');
+    $this->assertContactLinks($accounts, array('root', 'admin', 'no_contact'));
+
+    // Disable contact link for no_contact.
+    $this->userData->set('contact', $no_contact_account->id(), 'enabled', FALSE);
+    $this->drupalGet('test-contact-link');
+    $this->assertContactLinks($accounts, array('root', 'admin'));
+  }
+
+  /**
+   * Asserts whether certain users contact links appear on the page.
+   *
+   * @param array $accounts
+   *   All user objects used by the test.
+   * @param array $names
+   *   Users which should have contact links.
+   */
+  public function assertContactLinks(array $accounts, array $names) {
+    $result = $this->xpath('//div[contains(@class, "views-field-contact")]//a');
+    $this->assertEqual(count($result), count($names));
+    foreach ($names as $name) {
+      $account = $accounts[$name];
+
+      $uri = $account->uri();
+      $contact_uri = $uri['path'] . '/contact';
+      $result = $this->xpath('//div[contains(@class, "views-field-contact")]//a[contains(@href, :uri)]', array(':uri' => $contact_uri));
+      $this->assertTrue(count($result));
+    }
+  }
+
+}
diff --git a/core/modules/contact/tests/modules/contact_test_views/contact_test_views.info.yml b/core/modules/contact/tests/modules/contact_test_views/contact_test_views.info.yml
new file mode 100644
index 0000000..eb3b5e3
--- /dev/null
+++ b/core/modules/contact/tests/modules/contact_test_views/contact_test_views.info.yml
@@ -0,0 +1,11 @@
+name: 'Contact test views'
+type: module
+description: 'Provides default views for views contact tests.'
+package: Testing
+version: VERSION
+core: 8.x
+dependencies:
+  - contact
+  - views
+  - user
+hidden: true
diff --git a/core/modules/contact/tests/modules/contact_test_views/contact_test_views.module b/core/modules/contact/tests/modules/contact_test_views/contact_test_views.module
new file mode 100644
index 0000000..b3d9bbc
--- /dev/null
+++ b/core/modules/contact/tests/modules/contact_test_views/contact_test_views.module
@@ -0,0 +1 @@
+<?php
diff --git a/core/modules/contact/tests/modules/contact_test_views/test_views/views.view.test_contact_link.yml b/core/modules/contact/tests/modules/contact_test_views/test_views/views.view.test_contact_link.yml
new file mode 100644
index 0000000..341e925
--- /dev/null
+++ b/core/modules/contact/tests/modules/contact_test_views/test_views/views.view.test_contact_link.yml
@@ -0,0 +1,133 @@
+base_field: uid
+base_table: users
+core: 8.x
+description: ''
+status: '1'
+display:
+  default:
+    display_plugin: default
+    id: default
+    display_title: Master
+    position: '1'
+    display_options:
+      access:
+        type: perm
+        options:
+          perm: 'access content'
+        perm: 'access user profiles'
+      cache:
+        type: none
+        options: {  }
+      query:
+        type: views_query
+        options:
+          disable_sql_rewrite: '0'
+          distinct: '0'
+          slave: '0'
+          query_comment: ''
+          query_tags: {  }
+      exposed_form:
+        type: basic
+        options:
+          submit_button: Apply
+          reset_button: '0'
+          reset_button_label: Reset
+          exposed_sorts_label: 'Sort by'
+          expose_sort_order: '1'
+          sort_asc_label: Asc
+          sort_desc_label: Desc
+      pager:
+        type: full
+        options:
+          items_per_page: '10'
+          offset: '0'
+          id: '0'
+          total_pages: ''
+          expose:
+            items_per_page: '0'
+            items_per_page_label: 'Items per page'
+            items_per_page_options: '5, 10, 20, 40, 60'
+            items_per_page_options_all: '0'
+            items_per_page_options_all_label: '- All -'
+            offset: '0'
+            offset_label: Offset
+          tags:
+            previous: '‹ previous'
+            next: 'next ›'
+            first: '« first'
+            last: 'last »'
+          quantity: '9'
+      style:
+        type: default
+      row:
+        type: fields
+      fields:
+        name:
+          id: name
+          table: users
+          field: name
+          label: ''
+          alter:
+            alter_text: '0'
+            make_link: '0'
+            absolute: '0'
+            trim: '0'
+            word_boundary: '0'
+            ellipsis: '0'
+            strip_tags: '0'
+            html: '0'
+          hide_empty: '0'
+          empty_zero: '0'
+          link_to_user: '1'
+          overwrite_anonymous: '0'
+          relationship: none
+          group_type: group
+          admin_label: ''
+          exclude: '0'
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: '1'
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: '1'
+          empty: ''
+          hide_alter_empty: '1'
+          anonymous_text: ''
+          format_username: '1'
+        contact:
+          id: contact
+          table: users
+          field: contact
+          plugin_id: contact_link
+          exclude: ''
+      filters:
+        status:
+          value: '1'
+          table: users
+          field: status
+          id: status
+          expose:
+            operator: '0'
+          group: '1'
+      sorts: {  }
+      title: test_contact_link
+      header: {  }
+      footer: {  }
+      empty: {  }
+      relationships: {  }
+      arguments: {  }
+  page_1:
+    display_plugin: page
+    id: page_1
+    display_title: Page
+    position: '1'
+    display_options:
+      path: test-contact-link
+label: test_contact_link
+module: views
+id: test_contact_link
+tag: ''
+uuid: 41459805-9045-477c-aa37-f7e6d60b4132
+langcode: en
