To add to Peter's flurry of plugins + patches - here's a plugin I've been 
using in production for about 3 months that simply makes a copy (adds a 
recipient, hence bcc) for all/all incoming/all outgoing mail. I use it on 
a couple of client sites for archiving all their incoming and outgoing mail 
for a couple of weeks, in case of end-user loss.

Also available at http://www.openfusion.com.au/labs/qpsmtpd/.

Cheers,
Gavin

-- 
Open Fusion P/L - Open Source Business Solutions [ Linux - Perl - Apache ]
ph:  02 9875 5032                        fax: 02 9875 4317
web: http://www.openfusion.com.au        mob: 0403 171712
- Fashion is a variable, but style is a constant - Programming Perl
=head1 NAME

bcc

=head1 DESCRIPTION

Forwards a copy of all mail (or incoming and/or outgoing mail) to the 
given email address (useful for archiving etc.). Checks config files 
'bcc_ignore_mailfrom' and 'bcc_ignore_rcptto' for exceptions - these 
support bare username and '@domain' entries as wildcards as well as 
normal addresses. 

'bcc' should be called before the 'check_relay' plugin, since 
'incoming' processing uses a RCPT hook.

=head1 CONFIG

The following parameters can be passed to bcc:

=over 4

=item all <email>

Send a copy of all email to the given address.

=item incoming <email>

Send a copy of all incoming email to the given address. Mail is considered
incoming if it is going to a recipient with a domain in 'rcpthosts'.

=item outgoing <email>

Send a copy of all outgoing email to the given address. Mail is considered
outgoing if it is sent from a relay client i.e. the RELAYCLIENT environment 
variable is set.

=back

=head1 BUGS

Note that the definitions of incoming and outgoing mail mean that relayed
mail to a local domain is considered both incoming and outgoing, and will
be copied twice. This is a feature, not a bug. :-)

=head1 AUTHOR

Written by Gavin Carr <[EMAIL PROTECTED]>.

=cut

use Mail::Address;

sub register {
  my ($self, $qp, %arg) = @_;
  $self->{_bcc_all} = $arg{all};
  $self->{_bcc_incoming} = $arg{incoming};
  $self->{_bcc_outgoing} = $arg{outgoing};
  $self->register_hook("mail", "mail_handler");
  $self->register_hook("rcpt", "rcpt_handler") if $self->{_bcc_incoming};
  $self->register_hook("data_post", "bcc");
}

sub mail_handler {
  my ($self, $transaction, $sender) = @_;

  my $ignore = 0;
  for ($self->qp->config("bcc_ignore_mailfrom")) {
    $_ = lc;
    $ignore = 1,last if $_ eq lc $sender->address;
    $ignore = 1,last if substr($_,0,1) eq '@' && substr($_,1) eq lc $sender->host;
    $ignore = 1,last if index($_,'@') < 0 && $_ eq lc $sender->user;
  }
  $transaction->notes("bcc_ignore",1) if $ignore;

  return (DECLINED);
}

sub rcpt_handler {
  my ($self, $transaction, $rcpt) = @_;
  # Only copy once for multiple recipients
  return (DECLINED) 
    if $transaction->notes("bcc_ignore") || $transaction->notes('bcc_incoming');

  # Ignore only if *all* recipients are so marked
  my $ignore = 0;
  for ($self->qp->config("bcc_ignore_rcptto")) {
    $_ = lc;
    $ignore = 1,last if $_ eq lc $rcpt->address;
    $ignore = 1,last if substr($_,0,1) eq '@' && substr($_,1) eq lc $rcpt->host;
    $ignore = 1,last if index($_,'@') < 0 && $_ eq lc $rcpt->user;
  }
  if ($ignore) {
    $transaction->notes("bcc_ignore",1);
    return (DECLINED);
  }

  my $host = lc $rcpt->host;
  my @rcpthosts = ($self->qp->config("me"),$self->qp->config("rcpthosts"));
  for my $allowed (@rcpthosts) {
    ($allowed) =~ s/^\s*(\S+)/\L$1\E/;
    if ($host eq $allowed || 
       (substr($allowed,0,1) eq '.' && $host =~ m/\Q$allowed\E$/)) {
      $transaction->notes('bcc_incoming',1);
      last;
    }
  }

  return (DECLINED);
}

# Actual copying is deferred to data_post so as not to mess up the rcpt list
sub bcc
{
  my ($self, $transaction) = @_;
  return (DECLINED) if $transaction->notes("bcc_ignore");

  if ($self->{_bcc_all}) {
    my $rcpt = (Mail::Address->parse($self->{_bcc_all}))[0];
    $transaction->add_recipient($rcpt); 
    $self->log(3,"message copied to " . $self->{_bcc_all});
  }

  if ($self->{_bcc_outgoing} && exists $ENV{RELAYCLIENT}) {
    my $rcpt = (Mail::Address->parse($self->{_bcc_outgoing}))[0];
    $transaction->add_recipient($rcpt); 
    $self->log(3,"outgoing message copied to " . $self->{_bcc_outgoing});
  }

  if ($transaction->notes('bcc_incoming')) {
    my $rcpt = (Mail::Address->parse($self->{_bcc_incoming}))[0];
    $transaction->add_recipient($rcpt);
    $self->log(3,"incoming message copied to " . $self->{_bcc_incoming});
  }

  return (DECLINED); 
}

# tag: bcc plugin to copy mails to additional recipients

Reply via email to