diff --git a/mail_logger.module b/mail_logger.module
index 57f538a..e7c363c 100644
--- a/mail_logger.module
+++ b/mail_logger.module
@@ -328,3 +328,13 @@ function mail_logger_token_values($type, $object = NULL) {
   }
   return $values;
 }
+
+/**
+ * Implementation of hook_views_api().
+ */
+function mail_logger_views_api() {
+  return array(
+    'api' => 2,
+    'path' => drupal_get_path('module', 'mail_logger'),
+  );
+}
diff --git a/mail_logger.views.inc b/mail_logger.views.inc
new file mode 100644
index 0000000..e441856
--- /dev/null
+++ b/mail_logger.views.inc
@@ -0,0 +1,251 @@
+<?php
+/**
+ * @file
+ * Contains implementations of Views hooks.
+ */
+
+/**
+ * Implementation of hook_views_handlers().
+ */
+function mail_logger_views_handlers() {
+  $handlers = array();
+
+  // We piggyback onto the field handler Views provides for Locale module,
+  // as it does everything we need.
+  // However, to avoid adding a dependency on Locale, we need to tell Views
+  // about its location if the module is not enabled.
+  if (!module_exists('locale')) {
+    $handlers['handlers'] = array(
+      'views_handler_field_locale_language' => array(
+        'parent' => 'views_handler_field',
+        'path' => drupal_get_path('module', 'views') . '/modules/locale',
+      ),
+    );
+  }
+
+  $handlers['handlers']['mail_logger_handler_field_mail'] = array(
+    'parent' => 'views_handler_field',
+  );
+  $handlers['handlers']['mail_logger_handler_field_mail_logger_entry'] = array(
+    'parent' => 'views_handler_field',
+  );
+
+  return $handlers;
+}
+
+/**
+ * Implementation of hook_views_data().
+ */
+function mail_logger_views_data() {
+  // Basic table information.
+  $data['mail_logger']['table']['group']  = t('Mail log');
+
+  // Advertise this table as a possible base table
+  $data['mail_logger']['table']['base'] = array(
+    'field' => 'mlid',
+    'title' => t('Mail message'),
+    'help' => t('A record of a mail sent by the site.'),
+    'weight' => 10,
+  );
+
+  // Mail id
+  $data['mail_logger']['mlid'] = array(
+    'title' => t('Mail id'),
+    'help' => t('The serial id of the mail log entry.'),
+    'field' => array(
+      'handler' => 'mail_logger_handler_field_mail_logger_entry',
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_string',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_string',
+    ),
+  );
+
+  // Mail key
+  $data['mail_logger']['mailkey'] = array(
+    'title' => t('Mail key'),
+    'help' => t('The internal key the mail used for drupal_mail().'),
+    'field' => array(
+      'handler' => 'mail_logger_handler_field_mail_logger_entry',
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_string',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_string',
+    ),
+  );
+
+  // 'From' address
+  $data['mail_logger']['mail_from'] = array(
+    'title' => t('From address'),
+    'help' => t('The address the mail was sent from.'),
+    'field' => array(
+      'handler' => 'mail_logger_handler_field_mail',
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_string',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_string',
+    ),
+  );
+
+  // 'To' address
+  $data['mail_logger']['mail_to'] = array(
+    'title' => t('To address'),
+    'help' => t('The address the mail was sent to.'),
+    'field' => array(
+      'handler' => 'mail_logger_handler_field_mail',
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_string',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_string',
+    ),
+  );
+
+  // Subject
+  $data['mail_logger']['subject'] = array(
+    'title' => t('Subject'),
+    'help' => t('The subject line of the mail.'),
+    'field' => array(
+      'handler' => 'mail_logger_handler_field_mail_logger_entry',
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_string',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_string',
+    ),
+  );
+
+  // Body
+  $data['mail_logger']['body'] = array(
+    'title' => t('Body'),
+    'help' => t('The body text of the mail.'),
+    'field' => array(
+      'handler' => 'mail_logger_handler_field_mail_logger_entry',
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_string',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_string',
+    ),
+  );
+
+  // Date
+  $data['mail_logger']['date_sent'] = array(
+    'title' => t('Date sent'),
+    'help' => t('The date the email was sent.'),
+    'field' => array(
+      'handler' => 'views_handler_field_date',
+      'click sortable' => TRUE,
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort_date',
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_date',
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_date',
+    ),
+  );
+
+  // Language field
+  // We piggyback onto the field handler that Views provides for Locale module.
+  $data['mail_logger']['language'] = array(
+    'title' => t('Mail language'),
+    'help' => t('The language the email is in.'),
+    'field' => array(
+      'handler' => 'views_handler_field_locale_language',
+      'click sortable' => TRUE,
+    ),
+  );
+  // The argument and filter handlers need functions in Locale module, so
+  // we can only provide these if it's enabled.
+  if (module_exists('locale')) {
+    $data['mail_logger']['language']['filter'] = array(
+      'handler' => 'views_handler_filter_locale_language',
+    );
+    $data['mail_logger']['language']['argument'] = array(
+      'handler' => 'views_handler_argument_locale_language',
+    );
+  }
+
+  return $data;
+}
+
+/**
+ * Implement hook_date_api_tables().
+ *
+ * This hook together with hook_date_api_fields() tells Date module's handlers
+ * how to use our date field.
+ *
+ * These may as well live in this file, since it will be loaded by Views
+ * whenever Date module invokes both of these hooks, since it does so starting
+ * from its own hook_views_data().
+ */
+function mail_logger_date_api_tables() {
+  return array('mail_logger');
+}
+
+/**
+ * Implementation of hook_date_api_fields().
+ * on behalf of core fields.
+ *
+ * All modules that create custom fields that use the
+ * 'views_handler_field_date' handler can provide
+ * additional information here about the type of
+ * date they create so the date can be used by
+ * the Date API views date argument and date filter.
+ */
+function mail_logger_date_api_fields($field) {
+  if ($field == 'mail_logger.date_sent') {
+    return array(
+      // The type of date: DATE_UNIX, DATE_ISO, DATE_DATETIME.
+      'sql_type' => DATE_UNIX,
+      // Timezone handling options: 'none', 'site', 'date', 'utc'.
+      'tz_handling' => 'site',
+      // Needed only for dates that use 'date' tz_handling.
+      'timezone_field' => '',
+      // Needed only for dates that use 'date' tz_handling.
+      'offset_field' => '',
+      // Array of "table.field" values for related fields that should be
+      // loaded automatically in the Views SQL.
+      'related_fields' => array(),
+      // Granularity of this date field's db data.
+      'granularity' => array('year', 'month', 'day', 'hour', 'minute', 'second'),
+    );
+  }
+}
+
diff --git a/mail_logger_handler_field_mail.inc b/mail_logger_handler_field_mail.inc
new file mode 100644
index 0000000..9d82e05
--- /dev/null
+++ b/mail_logger_handler_field_mail.inc
@@ -0,0 +1,38 @@
+<?php
+/**
+ * Field handler to provide a mailto link for email fields.
+ */
+class mail_logger_handler_field_mail extends views_handler_field {
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['link'] = array('default' => 'mailto');
+    return $options;
+  }
+
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    $form['link'] = array(
+      '#title' => t('Link this field'),
+      '#type' => 'radios',
+      '#options' => array(
+        0 => t('No link'),
+        'mailto' => t("With a mailto:"),
+        'user' => t("User account, if one exists."),
+      ),
+      '#default_value' => $this->options['link'],
+    );
+  }
+
+  function render($values) {
+    if ($this->options['link'] == 'mailto') {
+      return l($values->{$this->field_alias}, "mailto:" . $values->{$this->field_alias});
+    }
+    elseif ($this->options['link'] == 'user') {
+      // Return a link to an account page if one exists; otherwise, fall back.
+      if ($account = mail_logger_email_user($values->{$this->field_alias})) {
+        return l($values->{$this->field_alias}, 'user/' . $account->uid);
+      }
+    }
+    return check_plain($values->{$this->field_alias});
+  }
+}
diff --git a/mail_logger_handler_field_mail_logger_entry.inc b/mail_logger_handler_field_mail_logger_entry.inc
new file mode 100644
index 0000000..5892b71
--- /dev/null
+++ b/mail_logger_handler_field_mail_logger_entry.inc
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Field handler to provide a link to the mail logger entry.
+ */
+class mail_logger_handler_field_mail_logger_entry extends views_handler_field {
+  /**
+   * Constructor to provide additional field to add.
+   */
+  function construct() {
+    parent::construct();
+    $this->additional_fields['mlid'] = array('table' => 'mail_logger', 'field' => 'mlid');
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['link_to_entry'] = array('default' => FALSE);
+    return $options;
+  }
+
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    $form['link_to_entry'] = array(
+      '#title' => t('Link this field to its mail logger entry'),
+      '#description' => t('This will override any other link you have set.'),
+      '#type' => 'checkbox',
+      '#default_value' => !empty($this->options['link_to_entry']),
+    );
+  }
+
+  /**
+   * Render whatever the data is as a link to the mail entry.
+   *
+   * Data should be made XSS safe prior to calling this function.
+   */
+  function render_link($data, $values) {
+    // Check the user has access.
+    if (!empty($this->options['link_to_entry']) && $data !== NULL && $data !== '' && user_access('access mail logger')) {
+      $this->options['alter']['make_link'] = TRUE;
+      $this->options['alter']['path'] = 'admin/reports/mail-logger/mail/' . $values->{$this->aliases['mlid']};
+    }
+    return $data;
+  }
+
+  function render($values) {
+    return $this->render_link(check_plain($values->{$this->field_alias}), $values);
+  }
+}
