for my $recipient (@recipients) {
       my $mail             = Mailer->new;
+      $mail->{record_id}   = $data->{invoice}->id,
+      $mail->{record_type} = 'invoice',
       $mail->{from}        = $data->{config}->email_sender || $::lx_office_conf{periodic_invoices}->{email_from};
       $mail->{to}          = $recipient;
       $mail->{bcc}         = $global_bcc;
 
                                 name => $params{email}->{attachment_filename} }];
       $mail->{message}    .=  "\n-- \n$signature";
       $mail->{message}     =~ s/\r//g;
-
+      $mail->{record_id}   =  $letter->id;
       $mail->send;
       unlink $result{file_name};
 
 
   { title => t8('Purchase delivery order'), type => 'purchase_delivery_order', model => 'DeliveryOrder',   number => 'donumber',  },
   { title => t8('Purchase Invoice'),        type => 'purchase_invoice',        model => 'PurchaseInvoice', number => 'invnumber', },
   { title => t8('Letter'),                  type => 'letter',                  model => 'Letter',          number => 'letternumber', description => 'subject', description_title => t8('Subject'), date => 'date', project => undef },
+  { title => t8('Email'),                   type => 'email_journal',           model => 'EmailJournal',    number => 'id', description => 'subject', description_title => t8('Subject'), },
 );
 
 my @link_types = map { +{ %link_type_defaults, %{ $_ } } } @link_type_specifics;
 
 
 __PACKAGE__->attr_sorted('attachments');
 
+sub compare_to {
+  my ($self, $other) = @_;
+
+  return -1 if  $self->sent_on && !$other->sent_on;
+  return  1 if !$self->sent_on &&  $other->sent_on;
+
+  my $result = 0;
+  $result    = $other->sent_on <=> $self->sent_on;
+  return $result || ($self->id <=> $other->id);
+}
+
 1;
+
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+SL::DB::EmailJournal - RDBO model for email journal
+
+=head1 SYNOPSIS
+
+This is a standard Rose::DB::Object based model and can be used as one.
+
+=head1 METHODS
+
+=over 4
+
+=item C<compare_to $self, $other>
+
+Compares C<$self> with C<$other> and returns the newer entry.
+
+=back
+
+=cut
+
 
     }
 
     # don't use rose retrieval here. too slow.
-    # instead use recursive sql to get all the linked record_links entrys, and retrieve the objects from there
+    # instead use recursive sql to get all the linked record_links entries and retrieve the objects from there
     my $query = <<"";
       WITH RECURSIVE record_links_rec_${wanted}(id, from_table, from_id, to_table, to_id, depth, path, cycle) AS (
         SELECT id, from_table, from_id, to_table, to_id,
                   'SL::DB::RequirementSpec' => sub { $_[0]->id },
                   'SL::DB::Letter'          => sub { $_[0]->letternumber },
                   'SL::DB::ShopOrder'       => sub { $_[0]->shop_ordernumber },
+                  'SL::DB::EmailJournal'    => sub { $_[0]->id },
                   UNKNOWN                   => '9999999999999999',
                 );
   my $number_xtor = sub {
               'SL::DB::PurchaseInvoice' => 150,
               'SL::DB::Letter'          => 200,
               'SL::DB::ShopOrder'       => 250,
+              'SL::DB::EmailJournal'    => 300,
               UNKNOWN                   => 999,
             );
   my $score_xtor = sub {
 
   smtp     => 'SL::Mailer::SMTP',
 );
 
+my %type_to_table = (
+  sales_quotation         => 'oe',
+  request_quotation       => 'oe',
+  sales_order             => 'oe',
+  purchase_order          => 'oe',
+  invoice                 => 'ar',
+  credit_note             => 'ar',
+  purchase_invoice        => 'ap',
+  letter                  => 'letter',
+  purchase_delivery_order => 'delivery_orders',
+  sales_delivery_order    => 'delivery_orders',
+);
+
 sub new {
   my ($type, %params) = @_;
   my $self = { %params };
 
   $error = $@ if !$ok;
 
+  # create journal and link to record
   $self->{journalentry} = $self->_store_in_journal;
+  $self->_create_record_link if $self->{journalentry};
 
   return $ok ? '' : ($error || "undefined error");
 }
   return $jentry->id;
 }
 
+
+sub _create_record_link {
+  my ($self) = @_;
+
+  # check for custom/overloaded types and ids (form != controller)
+  my $record_type = $self->{record_type} || $::form->{type};
+  my $record_id   = $self->{record_id}   || $::form->{id};
+
+  # you may send mails for unsaved objects (no record_id => unlinkable case)
+  if ($self->{journalentry} && $record_id && exists($type_to_table{$record_type})) {
+    RecordLinks->create_links(
+      mode       => 'ids',
+      from_table => $type_to_table{$record_type},
+      from_ids   => $record_id,
+      to_table   => 'email_journal',
+      to_id      => $self->{journalentry},
+    );
+  }
+}
+
 1;
+
+
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+SL::Mailer - Base class for sending mails from kivitendo
+
+=head1 SYNOPSIS
+
+  package SL::BackgroundJob::CreatePeriodicInvoices;
+
+  use SL::Mailer;
+
+  my $mail              = Mailer->new;
+  $mail->{from}         = $config{periodic_invoices}->{email_from};
+  $mail->{to}           = $email;
+  $mail->{subject}      = $config{periodic_invoices}->{email_subject};
+  $mail->{content_type} = $filename =~ m/.html$/ ? 'text/html' : 'text/plain';
+  $mail->{message}      = $output;
+
+  $mail->send;
+
+=head1 OVERVIEW
+
+Mail can be send from kivitendo via the sendmail command or the smtp protocol.
+
+
+=head1 INTERNAL DATA TYPES
+
+
+=over 2
+
+=item C<%mail_delivery_modules>
+
+  Currently two modules are supported either smtp or sendmail.
+
+=item C<%type_to_table>
+
+  Due to the lack of a single global mapping for $form->{type},
+  type is mapped to the corresponding database table. All types which
+  implement a mail action are currently mapped and should be mapped.
+  Type is either the value of the old form or the newer controller
+  based object type.
+
+=back
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item C<new>
+
+=item C<_create_driver>
+
+=item C<_cleanup_addresses>
+
+=item C<_create_address_headers>
+
+=item C<_create_message_id>
+
+=item C<_create_attachment_part>
+
+=item C<_create_message>
+
+=item C<send>
+
+  If a mail was send successfully the internal functions _store_in_journal
+  is called if email journaling is enabled. If _store_in_journal was executed
+  successfully and the calling form is already persistent (database id) a
+  record_link will be created.
+
+=item C<_all_recipients>
+
+=item C<_store_in_journal>
+
+=item C<_create_record_link $self->{journalentry}, $::form->{id}, $self->{record_id}>
+
+
+  If $self->{journalentry} and either $self->{record_id} or $::form->{id} (checked in
+  this order) exists a record link from record to email journal is created.
+  Will fail silently if record_link creation wasn't successful (same behaviour as
+  _store_in_journal).
+
+=item C<validate>
+
+=back
+
+=head1 BUGS
+
+Nothing here yet.
+
+=head1 AUTHOR
+
+=cut
 
   $output .= _sepa_transfer_list(          $groups{sepa_transfers},           %params) if $groups{sepa_transfers};
 
   $output .= _letter_list(                 $groups{letters},                  %params) if $groups{letters};
+  $output .= _email_journal_list(          $groups{email_journals},           %params) if $groups{email_journals};
 
   $output  = SL::Presenter->get->render('presenter/record/grouped_record_list', %params, output => $output);
 
     gl_transactions          => sub { (ref($_[0]) eq 'SL::DB::GLTransaction')                                           },
     bank_transactions        => sub { (ref($_[0]) eq 'SL::DB::BankTransaction') &&  $_[0]->id                           },
     letters                  => sub { (ref($_[0]) eq 'SL::DB::Letter')          &&  $_[0]->id                           },
+    email_journals           => sub { (ref($_[0]) eq 'SL::DB::EmailJournal')    &&  $_[0]->id                           },
   );
 
   my %groups;
   );
 }
 
+sub _email_journal_list {
+  my ($list, %params) = @_;
+
+  return record_list(
+    $list,
+    title   => $::locale->text('Email'),
+    type    => 'email_journal',
+    columns => [
+      [ $::locale->text('Sent on'), sub { $_[0]->sent_on->to_kivitendo(precision => 'seconds') } ],
+      [ $::locale->text('Subject'), sub { $_[0]->presenter->email_journal(display => 'table-cell') } ],
+      [ $::locale->text('Status'),  'status'                                                     ],
+      [ $::locale->text('From'),    'from'                                                       ],
+      [ $::locale->text('To'),      'recipients'                                                 ],
+    ],
+    %params,
+  );
+}
+
+
 1;
 
 __END__