You are here: start » plugins » spam » mailinglist_simple
You are currently not logged in! Enter your authentication credentials below to log in. You need to have cookies enabled to log in.
You don't have an account yet? Just get one: Register
Forgotten your password? Get a new one: Send new password
Plug-in Summary
| Plug-in name: | mailinglist_simple |
| Info: | a simple but effective mailinglist |
| Author: | Marc Sebastian Pelzer |
| Email: | not shown |
| Compatibility: | 3.x |
| Download: | http://search.cpan.org/~mpelzer/ |
How to add this plugin into your config/plugins:
# add this plugin BEFORE "rcpt_ok" # mailinglist_simple /usr/local/exim/virtual-domains/ # this plugin needs to run after all other "rcpt" plugins rcpt_ok
Example config/mailinglist_simpe file:
# format: # # <email of mailinglists> <only members can send email flag> <path to signature file> test@test.org 1 /usr/local/exim/signatures/test mylist@test.com /usr/local/exim/signatures/mylist openlist@test.net
Here comes the plugin:
=head1 NAME mailinglist_simple Version 1.2 by Marc Sebastian Pelzer http://search.cpan.org/~mpelzer/ =head1 DESCRIPTION This plugin adds very simple mailinglist functionality to alias-file based distribution lists. It reads its config-file config/mailinglist_simple and checks if the RCPT is a defined mailinglist. If true, it adds a "Reply-to" header to the email before it gets queued. It also adds a "Precedence: bulk" and "X-Mailing-List" header to prevent mail-loops/bounces from auto-reply applications. Its also possible to define a mailinglist as PUBLIC or PROTECTED - meaning if everyone can send an email to the list or just members of the list. You can also have a different signature for each list that will be added to the end of the mail. This plugin needs to be called in the config file config/plugins and must be BEFORE the "rcpt_ok" plugin! If you want PROTECTED maillinglist support, you must call the plugin with one parameter - the path and/or filename to your alias directory or alias file where your distribution lists are defined on the format: localpart: email@email.com,email2@email.com,email3@email.com Example config extries: mailinglist_simple mailinglist_simple /usr/local/exim/virtual-domains/ mailinglist_simple /etc/aliases Maybe you need to change the sourcecode to fit it to your alias file schema. Should not be too hard if you know Perl :) =cut use Qpsmtpd::DSN; sub register { my ($self, $qp, @args) = @_; if (@args > 0) { # check if we got an directory or file # if (-d $args[0] && -r $args[0]) { $self->{_ALIAS_DIRECTORY} = $args[0]; $self->{_PROTECTED_SUPPORT} = 'true'; $self->log(LOGINFO, "OK. Using alias directory '". $args[0] . "'"); } elsif (-f $args[0] && -r $args[0]) { $self->{_ALIAS_FILE} = $args[0]; $self->{_PROTECTED_SUPPORT} = 'true'; $self->log(LOGINFO, "OK. Using alias file '" . $args[0] . "'"); } else { die "Bad argument - need a valid alias directory or full path to a file: $args[0]"; } } else { $self->{_PROTECTED_SUPPORT} = 'false'; } } sub hook_rcpt { my ($self, $transaction, $recipient) = @_; my ($element, $list, $domain, $is_protected, $emails, $localpart, @emails, $line, $tmp, $isAValidSender, $signature); my @mailinglists = $self->qp->config("mailinglist_simple"); unless (@mailinglists) { $self->log(LOGDEBUG, "No configuration file config/mailinglist_simple found."); return DECLINED; } my $host = lc $recipient->host; my $from = lc($recipient->user) . '@' . $host; foreach $element (@mailinglists) { chomp($element); if ($element =~ m!^\s*\#! || $element =~ m!^\n$!) { next; } # ignore comments # split line into pieces # ($list, $domain, $is_protected, $signature) = ($element =~ m!^\s*([^\@]+)\@([\w\d\-\_\.]+)\s*([\d]?)\s*(\S*)!); # try to mach RCPT TO and defined lists # if ($list eq lc($recipient->user) && $domain eq $host) { if ($is_protected =~ m!^\d$! && $self->{_PROTECTED_SUPPORT} eq 'true') { # check if SENDER is member of the lists # $self->log(LOGNOTICE, "Found email to a PROTECTED mailinglist -> $from - checking SENDER"); if ($self->{_ALIAS_DIRECTORY}) { unless (-r $self->{_ALIAS_DIRECTORY} . "/$host") { $self->log(LOGWARN, "Error while try to open ALIAS file '" . $self->{_ALIAS_DIRECTORY} . "/$host"); return DENYSOFT; } open (ALIAS, $self->{_ALIAS_DIRECTORY} . "/$host"); } elsif ($self->{_ALIAS_FILE}) { unless (-r $self->{_ALIAS_FILE}) { $self->log(LOGWARN, "Error while try to open ALIAS file '" . $self->{_ALIAS_FILE}); return DENYSOFT; } open (ALIAS, $self->{_ALIAS_FILE}); } while ($line = <ALIAS>) { chomp($line); if ($line =~ m!^\s*\#! || $line =~ m!^\n$! || ! $line) { next; } ($localpart, $emails) = ($line =~ m!^\s*([^\:\s]+)\s*\:\s*(.+)$!); if ($localpart eq $list) { (@emails) = split(",", $emails); foreach $tmp (@emails) { $tmp =~ s!\s!!g; if (lc($tmp) eq lc($transaction->sender->address())) { ++$isAValidSender; } } } } close (ALIAS); if ($isAValidSender >= 1) { $self->log(LOGNOTICE, "Sender '" . $transaction->sender->address() . "' is a member of mailinglist '$from'. Accepting."); $transaction->notes("mailinglist", $from); # putting email into transaction notes to write the "Reply-to" header later... # add signature - if defined and available in the file-system # if (-e $signature && -r $signature) { $self->log(LOGNOTICE, "Adding signature '$signature'."); $transaction->notes("mailinglist_signature", $signature); } return DECLINED; } else { $self->log(LOGWARN, "Sender '" . $transaction->sender->address() . "' is NOT a member of mailinglist '$from'. Rejecting."); return Qpsmtpd::DSN->no_such_user("mail to $from not accepted from you"); } } else { # this is an PUBLIC list - everyone can send an email to it # $self->log(LOGNOTICE, "Found email to a PUBLIC mailinglist '$from'. Accepting."); $transaction->notes("mailinglist", $from); # putting email into transaction notes to write the "Reply-to" header later... # add signature - if defined and available in the file-system # if (-e $signature && -r $signature) { $self->log(LOGNOTICE, "Adding signature '$signature'."); $transaction->notes("mailinglist_signature", $signature); } return DECLINED; } } } return DECLINED; } sub hook_data_post { my ($self, $transaction) = @_; my ($line, $signature); unless ($transaction->notes("mailinglist")) { $self->log(LOGDEBUG, "Email is not an email to a mailinglists. Ignoring."); return DECLINED; } $self->log(LOGNOTICE, "Email is an email to a mailinglist -> " . $transaction->notes("mailinglist") . ". Adding Reply-to header element."); my $headers = $transaction->header(); if ($headers->get("Precedence") =~ m!(bulk|list|junk)!i || $headers->get("X-Mailing-List") || $headers->get("X-loop") eq $transaction->notes("mailinglist") || $headers->get("Auto-Submitted")) { $self->log(LOGWARN, "Loop detected or email from another mailinglist or auto-reply agent. Ignoring mail!"); return (DENY, "Loop detected!"); } $headers->replace("Reply-to", $transaction->notes("mailinglist")); $headers->replace("Sender", $transaction->notes("mailinglist")); # add header elements to prevent loops from auto-replies # $headers->add("Precedence", "bulk"); $headers->add("X-Mailing-List", "qpsmtpd mailinglist"); $headers->add("X-loop", $transaction->notes("mailinglist")); #$headers->replace("Envelope-From", ""); # we will add envelope handling later ... if ($transaction->notes("mailinglist_signature")) { open (SIG, $transaction->notes("mailinglist_signature")); while ($line = <SIG>) { $signature .= $line; } close (SIG); $transaction->body_write("\n\n--\n" . $signature); } return DECLINED; } 1;