=head1 NAME postfix-queue =head1 DESCRIPTION This plugin passes mails on to the postfix cleanup daemon. =head1 CONFIG The first optional parameter is the location of the cleanup socket. If it does not start with a ``/'', it is treated as a flag for cleanup (see below). If set, the environment variable POSTFIXQUEUE overrides this setting. All other parameters are flags for cleanup, no flags are enabled by default. Known flags are: =over 3 =item FLAG_FILTER Set the CLEANUP_FLAG_FILTER for cleanup. This enables the use of I, I or I in postfix' main.cf. =item FLAG_BCC_OK Setting this flag enables (for example) the I parameter =item FLAG_MAP_OK This flag enables the use of other recipient mappings (e.g. I) in postfix' cleanup. =back =cut use Qpsmtpd::Postfix; # # postfix' cleanup flags: use constant CLEANUP_FLAG_FILTER => (1 << 1); # /* Enable content filter */ use constant CLEANUP_FLAG_BCC_OK => (1 << 4); # /* Ok to add auto-BCC addresses */ use constant CLEANUP_FLAG_MAP_OK => (1 << 5); # /* Ok to map addresses */ sub register { my ($self, $qp, @args) = @_; $self->{_queue_flags} = 0; if (@args > 0) { if ($args[0] =~ m#^/#) { $self->{_queue_socket} = shift @args; } else { $self->{_queue_socket} = "/var/spool/postfix/public/cleanup"; } foreach (@args) { if ($_ eq 'FLAG_FILTER') { $self->{_queue_flags} |= CLEANUP_FLAG_FILTER; } elsif ($_ eq 'FLAG_BCC_OK') { $self->{_queue_flags} |= CLEANUP_FLAG_BCC_OK; } elsif ($_ eq 'FLAG_MAP_OK') { $self->{_queue_flags} |= CLEANUP_FLAG_MAP_OK; } else { $self->log(LOGWARN, "Ignoring unkown cleanup flag $_"); } } } else { $self->{_queue_socket} = "/var/spool/postfix/public/cleanup"; } $self->{_queue_socket} = $ENV{POSTFIXQUEUE} if $ENV{POSTFIXQUEUE}; } sub hook_queue { my ($self, $transaction) = @_; $transaction->notes('postfix-queue-flags', $self->{_queue_flags}); # $self->log(LOGDEBUG, "queue-flags=".$transaction->notes('postfix-queue-flags')); my ($status, $qid, $reason) = Qpsmtpd::Postfix->inject_mail($transaction); if ($status) { # this section needs to be kept in sync with the cleanup_stat_map # array found in Postfix source file src/global/cleanup_strerror.c # which in turn uses constants defined in src/global/cleanup_user.h if ($status & (1<<8)) { # CLEANUP_STAT_DEFER return(DENYSOFT, $reason || "service unavailable (#4.7.1)"); } elsif ($status & (1<<7)) { # CLEANUP_STAT_PROXY return(DENYSOFT, $reason || "proxy reject (#4.3.0)"); } elsif ($status & (1<<0)) { # CLEANUP_STAT_BAD return(DENYSOFT, $reason || "internal prototcal error (#4.3.0)"); } elsif ($status & (1<<6)) { # CLEANUP_STAT_RCPT return Qpsmtpd::DSN->addr_unspecified(DENY, $reason || "no recipients specified"); } elsif ($status & (1<<4)) { # CLEANUP_STAT_HOPS return Qpsmtpd::DSN->too_many_hops(DENY, $reason || "too many hops"); } elsif ($status & (1<<2)) { # CLEANUP_STAT_SIZE return Qpsmtpd::DSN->sys_msg_too_big(DENY, $reason || "message file too big"); } elsif ($status & (1<<3)) { # CLEANUP_STAT_CONT return Qpsmtpd::DSN->media_conv_prohibited(DENY, $reason || "message content rejected"); } elsif ($status & (1<<1)) { # CLEANUP_STAT_WRITE return (DECLINED, $reason || "queue file write error"); } else { # we have no idea why we're here. return (DECLINED, $reason || "unknown error from postfix/cleanup: $status"); } } $status and return (DECLINED, "Unable to queue message ($status, $reason)"); my $msg_id = $transaction->header->get('Message-Id') || ''; $msg_id =~ s/[\r\n].*//s; # don't allow newlines in the Message-Id here return (OK, "Queued! $msg_id (Queue-Id: $qid)"); } #vim: sw=2 ts=8