diff --git a/config/install/system.action.message_delete_action.yml b/config/install/system.action.message_delete_action.yml
new file mode 100644
index 0000000..e07db82
--- /dev/null
+++ b/config/install/system.action.message_delete_action.yml
@@ -0,0 +1,13 @@
+langcode: en
+status: true
+dependencies:
+  enforced:
+    module:
+      - contact_storage
+  module:
+    - contact_storage
+id: message_delete_action
+label: 'Delete message'
+type: contact_message
+plugin: message_delete_action
+configuration: {  }
diff --git a/config/install/views.view.contact_messages.yml b/config/install/views.view.contact_messages.yml
index 8250ad1..f2b7499 100644
--- a/config/install/views.view.contact_messages.yml
+++ b/config/install/views.view.contact_messages.yml
@@ -84,6 +84,59 @@ display:
       row:
         type: 'entity:contact_message'
       fields:
+        message_bulk_form:
+          id: message_bulk_form
+          table: contact_message
+          field: message_bulk_form
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: ''
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: false
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          action_title: 'With selection'
+          include_exclude: exclude
+          selected_actions: {  }
+          entity_type: contact_message
+          plugin_id: message_bulk_form
         subject:
           id: subject
           table: contact_message
@@ -445,10 +498,14 @@ display:
       display_extenders: {  }
     cache_metadata:
       contexts:
-        0: user
-        2: cache.context.url
-        3: language
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - user.permissions
       cacheable: false
+      max-age: 0
+      tags: {  }
   page_1:
     display_plugin: page
     id: page_1
@@ -467,7 +524,11 @@ display:
       display_extenders: {  }
     cache_metadata:
       contexts:
-        0: user
-        2: cache.context.url
-        3: language
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url
+        - url.query_args
+        - user.permissions
       cacheable: false
+      max-age: 0
+      tags: {  }
diff --git a/config/schema/contact_storage.schema.yml b/config/schema/contact_storage.schema.yml
index 476314b..5ad348d 100644
--- a/config/schema/contact_storage.schema.yml
+++ b/config/schema/contact_storage.schema.yml
@@ -52,3 +52,7 @@ contact_storage.settings:
     send_html:
       type: boolean
       label: 'Whether the mail should be sent as HTML'
+
+action.configuration.message_delete_action:
+  type: action_configuration_default
+  label: 'Delete message configuration'
diff --git a/config/schema/contact_storage.views.schema.yml b/config/schema/contact_storage.views.schema.yml
index b000275..1ea1cce 100644
--- a/config/schema/contact_storage.views.schema.yml
+++ b/config/schema/contact_storage.views.schema.yml
@@ -1,3 +1,7 @@
 views.field.contact_form:
   type: views_field
   label: 'Contact form'
+
+views.field.message_bulk_form:
+  type: views_field_bulk_form
+  label: 'Contact Message bulk form'
diff --git a/contact_storage.install b/contact_storage.install
index ba3da64..6c4d1f0 100644
--- a/contact_storage.install
+++ b/contact_storage.install
@@ -5,6 +5,9 @@
  * Contains install and update hooks.
  */
 
+use Drupal\Core\Config\InstallStorage;
+use Drupal\Core\Config\FileStorage;
+
 /**
  * Implements hook_install().
  */
@@ -43,3 +46,19 @@ function _contact_storage_ensure_fields() {
     $entity_definition_update_manager->installFieldStorageDefinition($field_name, 'contact_message', 'contact_storage', $field_definition);
   }
 }
+
+/**
+ * Save the bulk delete action to config.
+ */
+function contact_storage_update_8002() {
+  $entity_type_manager = \Drupal::entityTypeManager();
+  $module_handler = \Drupal::moduleHandler();
+
+  // Save the bulk delete action to config.
+  $config_install_path = $module_handler->getModule('contact_storage')->getPath() . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY;
+  $storage = new FileStorage($config_install_path);
+  $entity_type_manager
+    ->getStorage('action')
+    ->create($storage->read('system.action.message_delete_action'))
+    ->save();
+}
diff --git a/contact_storage.routing.yml b/contact_storage.routing.yml
index e21921e..b0c3c79 100644
--- a/contact_storage.routing.yml
+++ b/contact_storage.routing.yml
@@ -5,3 +5,9 @@ contact_storage.settings:
     _title: 'Contact settings'
   requirements:
     _permission: 'administer contact forms'
+entity.contact.multiple_delete_confirm:
+  path: '/admin/structure/contact/messages/delete'
+  defaults:
+    _form: '\Drupal\contact_storage\Form\DeleteMultiple'
+  requirements:
+    _permission: 'administer contact forms'
diff --git a/src/Form/DeleteMultiple.php b/src/Form/DeleteMultiple.php
new file mode 100644
index 0000000..c1f999b
--- /dev/null
+++ b/src/Form/DeleteMultiple.php
@@ -0,0 +1,140 @@
+<?php
+
+namespace Drupal\contact_storage\Form;
+
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Form\ConfirmFormBase;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Url;
+use Drupal\user\PrivateTempStoreFactory;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpFoundation\RedirectResponse;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\StringTranslation\TranslationInterface;
+
+/**
+ * Provides a message deletion confirmation form.
+ */
+class DeleteMultiple extends ConfirmFormBase {
+
+  /**
+   * The array of messages to delete.
+   *
+   * @var string[][]
+   */
+  protected $messages = array();
+
+  /**
+   * The tempstore factory.
+   *
+   * @var \Drupal\user\PrivateTempStoreFactory
+   */
+  protected $privateTempStoreFactory;
+
+  /**
+   * The message storage.
+   *
+   * @var \Drupal\Core\Entity\EntityStorageInterface
+   */
+  protected $storage;
+
+  /**
+   * The current user.
+   *
+   * @var \Drupal\Core\Session\AccountInterface
+   */
+  protected $account;
+
+  /**
+   * Constructs a DeleteMultiple form object.
+   *
+   * @param \Drupal\user\PrivateTempStoreFactory $temp_store_factory
+   *   The tempstore factory.
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager.
+   * @param \Drupal\Core\Session\AccountInterface $account
+   *   The current user.
+   * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
+   *   The String translation.
+   */
+  public function __construct(PrivateTempStoreFactory $temp_store_factory, EntityTypeManagerInterface $entity_type_manager, AccountInterface $account, TranslationInterface $string_translation) {
+    $this->privateTempStoreFactory = $temp_store_factory;
+    $this->storage = $entity_type_manager->getStorage('contact_message');
+    $this->account = $account;
+    $this->setStringTranslation($string_translation);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('user.private_tempstore'),
+      $container->get('entity_type.manager'),
+      $container->get('current_user'),
+      $container->get('string_translation')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'message_multiple_delete_confirm';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getQuestion() {
+    return $this->formatPlural(count($this->messages), 'Are you sure you want to delete this message?', 'Are you sure you want to delete these messages?');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCancelUrl() {
+    return new Url('entity.contact_message.collection');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfirmText() {
+    return t('Delete');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state) {
+    $this->messages = $this->privateTempStoreFactory->get('message_multiple_delete_confirm')->get($this->account->id());
+    if (empty($this->messages)) {
+      return new RedirectResponse($this->getCancelUrl()->setAbsolute()->toString());
+    }
+
+    $form['messages'] = [
+      '#theme' => 'item_list',
+      '#items' => array_map(function ($message) {
+        return $message->label();
+      }, $this->messages),
+    ];
+    return parent::buildForm($form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+
+    if ($form_state->getValue('confirm') && !empty($this->messages)) {
+      $this->storage->delete($this->messages);
+      $this->privateTempStoreFactory->get('message_multiple_delete_confirm')->delete($this->account->id());
+      $count = count($this->messages);
+      $this->logger('contact')->notice('Deleted @count messages.', ['@count' => $count]);
+      drupal_set_message($this->stringTranslation->formatPlural($count, 'Deleted 1 message.', 'Deleted @count messages.'));
+    }
+    $form_state->setRedirect('entity.contact_message.collection');
+  }
+
+}
diff --git a/src/MessageViewsData.php b/src/MessageViewsData.php
index 3af8031..6ff6503 100644
--- a/src/MessageViewsData.php
+++ b/src/MessageViewsData.php
@@ -28,6 +28,14 @@ class MessageViewsData extends EntityViewsData {
       ),
     );
 
+    $data['contact_message']['message_bulk_form'] = array(
+      'title' => $this->t('Message operations bulk form'),
+      'help' => $this->t('Add a form element that lets you run operations on multiple messages.'),
+      'field' => array(
+        'id' => 'message_bulk_form',
+      ),
+    );
+
     return $data;
   }
 
diff --git a/src/Plugin/Action/DeleteMessage.php b/src/Plugin/Action/DeleteMessage.php
new file mode 100644
index 0000000..5498fb3
--- /dev/null
+++ b/src/Plugin/Action/DeleteMessage.php
@@ -0,0 +1,93 @@
+<?php
+
+namespace Drupal\contact_storage\Plugin\Action;
+
+use Drupal\Core\Action\ActionBase;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\user\PrivateTempStoreFactory;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Redirects to a message deletion form.
+ *
+ * @Action(
+ *   id = "message_delete_action",
+ *   label = @Translation("Delete message"),
+ *   type = "contact_message",
+ *   confirm_form_route_name = "entity.contact.multiple_delete_confirm"
+ * )
+ */
+class DeleteMessage extends ActionBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * The tempstore object.
+   *
+   * @var \Drupal\user\SharedTempStore
+   */
+  protected $privateTempStore;
+
+  /**
+   * The current user.
+   *
+   * @var \Drupal\Core\Session\AccountInterface
+   */
+  protected $currentUser;
+
+  /**
+   * Constructs a new DeleteMessage object.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin ID for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\user\PrivateTempStoreFactory $temp_store_factory
+   *   The tempstore factory.
+   * @param AccountInterface $current_user
+   *   Current user.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, PrivateTempStoreFactory $temp_store_factory, AccountInterface $current_user) {
+    $this->currentUser = $current_user;
+    $this->privateTempStore = $temp_store_factory->get('message_multiple_delete_confirm');
+
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('user.private_tempstore'),
+      $container->get('current_user')
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function executeMultiple(array $entities) {
+    $this->privateTempStore->set($this->currentUser->id(), $entities);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function execute($object = NULL) {
+    $this->executeMultiple(array($object));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
+    /** @var \Drupal\contact\MessageInterface $object */
+    return $object->access('delete', $account, $return_as_object);
+  }
+
+}
diff --git a/src/Plugin/views/field/MessageBulkForm.php b/src/Plugin/views/field/MessageBulkForm.php
new file mode 100644
index 0000000..4afee92
--- /dev/null
+++ b/src/Plugin/views/field/MessageBulkForm.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace Drupal\contact_storage\Plugin\views\field;
+
+use Drupal\system\Plugin\views\field\BulkForm;
+
+/**
+ * Defines a contact message operations bulk form element.
+ *
+ * @ViewsField("message_bulk_form")
+ */
+class MessageBulkForm extends BulkForm {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function emptySelectedMessage() {
+    return $this->t('No message selected.');
+  }
+
+}
diff --git a/src/Tests/BulkFormTest.php b/src/Tests/BulkFormTest.php
new file mode 100644
index 0000000..a78d10a
--- /dev/null
+++ b/src/Tests/BulkFormTest.php
@@ -0,0 +1,78 @@
+<?php
+
+namespace Drupal\contact_storage\Tests;
+
+use Drupal\Component\Utility\SafeMarkup;
+use Drupal\views\Tests\ViewTestData;
+
+/**
+ * Tests a contact message bulk form.
+ *
+ * @group contact_storage
+ * @see \Drupal\contact_storage\Plugin\views\field\MessageBulkForm
+ */
+class BulkFormTest extends ContactStorageTestBase {
+
+  /**
+   * Modules to be enabled.
+   *
+   * @var array
+   */
+  public static $modules = array(
+    'contact_storage',
+    'contact_test_views',
+    'language',
+  );
+
+  /**
+   * Views used by this test.
+   *
+   * @var array
+   */
+  public static $testViews = array('test_contact_message_bulk_form');
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::Setup();
+    // Create and login administrative user.
+    $admin_user = $this->drupalCreateUser(array(
+      'administer contact forms',
+      'administer modules',
+    ));
+    $this->drupalLogin($admin_user);
+    $this->drupalGet('admin/modules');
+    // Create first valid contact form.
+    $mail = 'simpletest@example.com';
+    $this->addContactForm('test_id', 'test_label', $mail, '', TRUE);
+    $this->assertText(t('Contact form test_label has been added.'));
+    $this->drupalLogout();
+
+    // Ensure that anonymous can submit site-wide contact form.
+    user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access site-wide contact form'));
+    $this->drupalGet('contact');
+    $this->assertText(t('Your email address'));
+    // Submit contact form few times.
+    for ($i = 1; $i <= 5; $i++) {
+      $this->submitContact($this->randomMachineName(), $mail, $this->randomMachineName(), 'test_id', $this->randomMachineName());
+      $this->assertText(t('Your message has been sent.'));
+    }
+  }
+
+  /**
+   * Test multiple deletion.
+   */
+  public function testBulkDeletion() {
+    $this->drupalGet('contact');
+    ViewTestData::createTestViews(get_class($this), array('contact_test_views'));
+    // Check the operations are accessible to the administer permission user.
+    $this->drupalLogin($this->drupalCreateUser(array('administer contact forms')));
+    $this->drupalGet('test-contact-message-bulk-form');
+    $elements = $this->xpath('//select[@id="edit-action"]//option');
+    $this->assertIdentical(count($elements), 1, 'All contact message operations are found.');
+    $this->drupalPostForm('test-contact-message-bulk-form', [], t('Apply'));
+    $this->assertText(t('No message selected.'));
+  }
+
+}
diff --git a/tests/modules/contact_test_views/contact_test_views.info.yml b/tests/modules/contact_test_views/contact_test_views.info.yml
new file mode 100644
index 0000000..3157e2d
--- /dev/null
+++ b/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
+  - contact_storage
+  - views
+  - language
diff --git a/tests/modules/contact_test_views/test_views/views.view.test_contact_message_bulk_form.yml b/tests/modules/contact_test_views/test_views/views.view.test_contact_message_bulk_form.yml
new file mode 100644
index 0000000..fd7f0f3
--- /dev/null
+++ b/tests/modules/contact_test_views/test_views/views.view.test_contact_message_bulk_form.yml
@@ -0,0 +1,188 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - contact
+    - contact_storage
+id: test_contact_message_bulk_form
+label: ''
+module: views
+description: ''
+tag: ''
+base_table: contact_message
+base_field: id
+core: 8.x
+display:
+  default:
+    display_plugin: default
+    id: default
+    display_title: Master
+    position: null
+    display_options:
+      style:
+        type: table
+      row:
+        type: fields
+      fields:
+        message_bulk_form:
+          id: message_bulk_form
+          table: contact_message
+          field: message_bulk_form
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: 'Message operations bulk form'
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          action_title: 'With selection'
+          include_exclude: exclude
+          selected_actions: {  }
+          entity_type: contact_message
+          plugin_id: message_bulk_form
+        subject:
+          table: contact_message
+          field: subject
+          id: subject
+          entity_type: null
+          entity_field: subject
+          plugin_id: field
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Subject
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: string
+          settings: {  }
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+      filters: {  }
+      sorts:
+        id:
+          id: id
+          table: contact_message
+          field: id
+          relationship: none
+          group_type: group
+          admin_label: ''
+          order: ASC
+          exposed: false
+          expose:
+            label: ''
+          entity_type: contact_message
+          entity_field: id
+          plugin_id: standard
+      title: ''
+      header: {  }
+      footer: {  }
+      empty: {  }
+      relationships: {  }
+      arguments: {  }
+      display_extenders: {  }
+    cache_metadata:
+      max-age: 0
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url.query_args
+      tags: {  }
+  page_1:
+    display_plugin: page
+    id: page_1
+    display_title: Page
+    position: 1
+    display_options:
+      display_extenders: {  }
+      path: test-contact-message-bulk-form
+    cache_metadata:
+      max-age: 0
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url.query_args
+      tags: {  }
