diff options
Diffstat (limited to 'contrib/multidrop')
-rw-r--r-- | contrib/multidrop | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/contrib/multidrop b/contrib/multidrop new file mode 100644 index 00000000..37f87b4c --- /dev/null +++ b/contrib/multidrop @@ -0,0 +1,236 @@ +From mlievaart@orion.nl Mon Jan 10 10:46:33 2000 +From: Martijn Lievaart <mlievaart@orion.nl> +To: Eric S. Raymond <esr@thyrsus.com> +Date: zondag 9 januari 2000 0:38 +Subject: Re: Thanks for fetchmail and a solution to the multidrop problem (I +Status: O +Content-Length: 8086 +Lines: 226 + +think) + +Hello Eric, + +Let me first state that I'm no sendmail nor unix guru, so although this +seems to work, I certainly would not say this is the "best" solution. In +fact I would welcome all comments to make this better. In particular, it +seems that that the mailertable feature was made just for this, but I'm +still studying that. + +Also, This mail will have lines wrapped. I will put up this on a website +asap, so people can download the relevant portions. In the meantime, I'm +using (stuck on) Outlook, so I won't even attempt to format this mail. +Accept my apoligies and try to mentally reconnect the lines. + +Finally, this mail is a bit lengthy, but I guess it is better to get all +information in, so please bear with me. + +After some very frustrating attempts to get multidrop to work reliably, it +suddenly hit me. When sendmail has translated the recipient to the mailbox, +the recipient is gone (in the cases we're talking about). So the solution is +not to let sendmail do this translation (completely). + +The trick is to let a custom MDA be called with both the mailbox and the +full recipient name. This MDA then just stuffs it in the correct mailbox +after adding the appropriate headers. Luckily I hit on the formail utility. +It reformats a mailmessage and does just what I wanted. Specifically my +script uses it to: +- add a custom header (default: "Delivered-To:") with the recipient +- rewrite the message-ID, so fetchmail will download the same message +multiple times. +- add another header, just for fun. + +The rewriting of the message-ID is needed because fetchmail will suppress +multiple messages with the same ID, normally a good idea, but now it gets in +the way. A switch on fetchmail to suppress this behaviour would be great. + +At first I hardcoded the domains in the sendmail.cf, but I quickly set out +to do one better and came up with the following solution. In sendmail.cf, +add the following line somewhere at the top. + +Kmultidroptable hash -o /etc/mail/multidroptable + +this defines a table for all domains we want to use multidrop for. The +format of this file is multiple lines of the format: +<domain> <mailbox> + +e.g: +mailtest.orion.nl mailtest +mailtest2.orion.nl mailtest +mailtest3.orion.nl mailtest +bvh-communicatie.nl b.bvh +krakatau.nl b.bvh +personeelzaak.nl b.bvh +maslowassociates.nl b.bvh +rtij.nl rtij + +Of course, create a .db file with makemap. Also, the domains must be added +to class w, so they should be added to your sendmail.cw or RelayTo file, or +whatever you use. + +Now add to sendmail.cf: + +R$+ < @ $* . > $: <MULTIDROP> $(multidroptable $2 +$: <NO> $) <?> $1 < @ $2 . > +R<MULTIDROP> <NO> <?> $* $: $1 +R<MULTIDROP> $+ <?> $+ < @ $* . > $#drop $@ $2 @ $3 $: $1 + +These lines should be above the existing lines that read: + +# short circuit local delivery so forwarded email works +R$=L < @ $=w . > $#local $: @ $1 special local names +R$+ < @ $=w . > $#local $: $1 regular local name + +This works as follows (in fact these comments are above my modification in +our sendmail.cf). +# +# MLI. Any drop host gets passed to the drop script +# +# The first rule looks up the domain in the multidrop table. +# The input at this point is always: +# user@<dom.ain.> +# If found, the resulting line looks like this: +# <MULTIDROP> mailbox <?> user@<dom.ain.> +# if not found, the resulting line will be: +# <MULTIDROP> <NO> <?> user@<dom.ain.> +# The second line restores the "not found" case back to user@<dom.ain.> +# So if this domain was found in the multidroptable, we still have a line +starting with <MULTIDROP> +# as shown above. The third line hands this to the drop script. +# +# Note that the user ($:) is the mailbox this message should be stuffed in, +the host ($@) is the full +# user@<dom.ain>. This is how the dropscript expects it. +# + +I guess sendmail guru's are now laughing their pants off, and I hope someone +will show me a better way to achieve this. For now, it works. + +Next, we need to define mailer drop (somewhere in the sendmail.cf) + +# +# multidrop pop3 support. +# + +Mdrop, P=/usr/local/bin/dropmail, F=lFS, + T=X-Unix, + A=dropmail $u $h + +The S flag here is crucial, otherwise the dropmail script won't run as root, +and under linux (==bash) suid scripts are not permited. I gather most unices +now disalow suid scripts, so this would be necessary on most unices. There +probably are other flags that would make this better, but this works, so I +decided to divert my attention to other tasks at hand (busy, busy, busy.... +;^>). + +Now we only need the dropmail script, /usr/local/bin/dropmail, mode 700. It +looks big, but effectively one pipeline does the real work. The rest is +configuration, error checking and locking the mailbox. + +#!/bin/bash + +# +# Script to force a mail message in a format that fetchmail will recognise. +# use as a MDA from sendmail. Must be executed with F=S. +# + +# +# Configuration: +# +maildir=/var/spool/mail +envelope=Delivered-To: + +# +# set PATH to a known value to avoid some security issues +# +export PATH=/bin:/usr/bin + +# +# +# +to=$2 +user=$1 +mbox=$maildir/$user + +# +# If the mailbox does not exist, create it. Note that we act pretty +paranoid, this is hopefully +# resistant to symlink attacks +# +if [ ! -f $mbox ] +then + oldumask=`umask` + umask 077 + touch $mbox + chmod 660 $mbox || exit 1 + chown $user $mbox || exit 1 + chgrp mail $mbox || exit 1 + umask $oldumask +fi + +# First lock the mailbox, if this doesn't succeed in 64 seconds, give up and +send +# mail to postmaster. +# If this period is to short, increase the retries (-r flag to lockfile) +# +# Then run the message through formail to get it into the right mailbox +format with the +# right headers added. +# +# Delivered-To will make fetchmail propagate this mail to the correct user +when +# run with '-E "Delivered-To"'. Set this in the advanced settings of the +TeamInternet f.i. +# (if you changed the envelope at the start of this script, adapt this +accordingly) +# +# We also muck up the messageid, so fetchmail will never skip a message on +the basis of +# duplicate messageIDs. The -i "Message-ID" will rename the old message ID, +the -a will +# add a new one. +# +# Lastly, we add a header indicating which host did the rewriting. +# + +if lockfile -r 8 $mbox.lock >/dev/null 2>&1 +then + cat - | formail -i "$envelope <$to>" -i "Message-ID:" -a +"Message-ID:" -i "X-Multidrop-Processing: <`hostname`>" >>$mbox + rm -f $mbox.lock +else + (echo "Subject: Cannot lock mailbox for $user" & cat -) | +/usr/lib/sendmail postmaster +fi + +# +# EOF +# + +This obviously is very Linux (even RedHat?) dependant, locking mailboxes, +creating mailboxes with the right permissions, probably even bash dependent. +I would say that it should be fairly easy to port to other systems, but +alas, my unix knowledge is lacking for that. I'll also rewrite it someday, +a.o. that umask handling can be done much better and the location of the +sendmail binairy should not be fixed. + +Now the only thing left to do is to retrieve the mail with fetchmail, using +'envelope "Delivered-To:"' in the poll line. The above script has added this +line, so this is all that fetchmail needs. + +All parts of this solution need carefull examination. In particular I think +the new rule lines may not catch all cases, although they worked for +everything I threw at them and work satisfactorily in production. I'm also +wondering if there is a more standard way to drop something in a mailbox. I +yet have to investigate procmail, but all other MDA's mucked with the +message and effectively undid my carefully added header. I'll experiment +some more and rethink it all as I learn more. + +I'm still wondering, if I can get formail to include another received +line.... "Received from localhost by dropmail for <user>...." to make it +work without the envelope flag. Well I'll have to experiment. Do you know if +there is a header I can add so fetchmail works out-of-the-box? + +Regards, +Martijn Lievaart + |