]> Pileus Git - ~andy/fetchmail/blob - contrib/multidrop
Complete Dominik's name.
[~andy/fetchmail] / contrib / multidrop
1 From mlievaart@orion.nl  Mon Jan 10 10:46:33 2000
2 From: Martijn Lievaart <mlievaart@orion.nl>
3 To: Eric S. Raymond <esr@thyrsus.com>
4 Date: zondag 9 januari 2000 0:38
5 Subject: Re: Thanks for fetchmail and a solution to the multidrop problem (I
6 Status: O
7 Content-Length: 8086
8 Lines: 226
9
10 think)
11
12 Hello Eric,
13
14 Let me first state that I'm no sendmail nor unix guru, so although this
15 seems to work, I certainly would not say this is the "best" solution. In
16 fact I would welcome all comments to make this better. In particular, it
17 seems that that the mailertable feature was made just for this, but I'm
18 still studying that.
19
20 Also, This mail will have lines wrapped. I will put up this on a website
21 asap, so people can download the relevant portions. In the meantime, I'm
22 using (stuck on) Outlook, so I won't even attempt to format this mail.
23 Accept my apoligies and try to mentally reconnect the lines.
24
25 Finally, this mail is a bit lengthy, but I guess it is better to get all
26 information in, so please bear with me.
27
28 After some very frustrating attempts to get multidrop to work reliably, it
29 suddenly hit me. When sendmail has translated the recipient to the mailbox,
30 the recipient is gone (in the cases we're talking about). So the solution is
31 not to let sendmail do this translation (completely).
32
33 The trick is to let a custom MDA be called with both the mailbox and the
34 full recipient name. This MDA then just stuffs it in the correct mailbox
35 after adding the appropriate headers. Luckily I hit on the formail utility.
36 It reformats a mailmessage and does just what I wanted. Specifically my
37 script uses it to:
38 - add a custom header (default: "Delivered-To:") with the recipient
39 - rewrite the message-ID, so fetchmail will download the same message
40 multiple times.
41 - add another header, just for fun.
42
43 The rewriting of the message-ID is needed because fetchmail will suppress
44 multiple messages with the same ID, normally a good idea, but now it gets in
45 the way. A switch on fetchmail to suppress this behaviour would be great.
46
47 At first I hardcoded the domains in the sendmail.cf, but I quickly set out
48 to do one better and came up with the following solution. In sendmail.cf,
49 add the following line somewhere at the top.
50
51 Kmultidroptable hash -o /etc/mail/multidroptable
52
53 this defines a table for all domains we want to use multidrop for. The
54 format of this file is multiple lines of the format:
55 <domain>    <mailbox>
56
57 e.g:
58 mailtest.orion.nl       mailtest
59 mailtest2.orion.nl      mailtest
60 mailtest3.orion.nl      mailtest
61 bvh-communicatie.nl     b.bvh
62 krakatau.nl             b.bvh
63 personeelzaak.nl        b.bvh
64 maslowassociates.nl     b.bvh
65 rtij.nl                 rtij
66
67 Of course, create a .db file with makemap. Also, the domains must be added
68 to class w, so they should be added to your sendmail.cw or RelayTo file, or
69 whatever you use.
70
71 Now add to sendmail.cf:
72
73 R$+ < @ $* . >                          $: <MULTIDROP> $(multidroptable $2
74 $: <NO> $) <?> $1 < @ $2 . >
75 R<MULTIDROP> <NO> <?> $*                $: $1
76 R<MULTIDROP> $+ <?> $+ < @ $* . >       $#drop $@ $2 @ $3 $: $1
77
78 These lines should be above the existing lines that read:
79
80 # short circuit local delivery so forwarded email works
81 R$=L < @ $=w . >        $#local $: @ $1         special local names
82 R$+ < @ $=w . >         $#local $: $1                   regular local name
83
84 This works as follows (in fact these comments are above my modification in
85 our sendmail.cf).
86 #
87 # MLI. Any drop host gets passed to the drop script
88 #
89 # The first rule looks up the domain in the multidrop table.
90 # The input at this point is always:
91 #       user@<dom.ain.>
92 #  If found, the resulting line looks like this:
93 #       <MULTIDROP> mailbox <?> user@<dom.ain.>
94 # if not found, the resulting line will be:
95 #       <MULTIDROP> <NO> <?> user@<dom.ain.>
96 # The second line restores the "not found" case back to user@<dom.ain.>
97 # So if this domain was found in the multidroptable, we still have a line
98 starting with <MULTIDROP>
99 # as shown above. The third line hands this to the drop script.
100 #
101 # Note that the user ($:) is the mailbox this message should be stuffed in,
102 the host ($@) is the full
103 # user@<dom.ain>. This is how the dropscript expects it.
104 #
105
106 I guess sendmail guru's are now laughing their pants off, and I hope someone
107 will show me a better way to achieve this. For now, it works.
108
109 Next, we need to define mailer drop (somewhere in the sendmail.cf)
110
111 #
112 # multidrop pop3 support.
113 #
114
115 Mdrop,          P=/usr/local/bin/dropmail, F=lFS,
116                 T=X-Unix,
117                 A=dropmail $u $h
118
119 The S flag here is crucial, otherwise the dropmail script won't run as root,
120 and under linux (==bash) suid scripts are not permited. I gather most unices
121 now disalow suid scripts, so this would be necessary on most unices. There
122 probably are other flags that would make this better, but this works, so I
123 decided to divert my attention to other tasks at hand (busy, busy, busy....
124 ;^>).
125
126 Now we only need the dropmail script, /usr/local/bin/dropmail, mode 700. It
127 looks big, but effectively one pipeline does the real work. The rest is
128 configuration, error checking and locking the mailbox.
129
130 #!/bin/bash
131
132 #
133 # Script to force a mail message in a format that fetchmail will recognise.
134 # use as a MDA from sendmail. Must be executed with F=S.
135 #
136
137 #
138 # Configuration:
139 #
140 maildir=/var/spool/mail
141 envelope=Delivered-To:
142
143 #
144 # set PATH to a known value to avoid some security issues
145 #
146 export PATH=/bin:/usr/bin
147
148 #
149 #
150 #
151 to=$2
152 user=$1
153 mbox=$maildir/$user
154
155 #
156 # If the mailbox does not exist, create it. Note that we act pretty
157 paranoid, this is hopefully
158 # resistant to symlink attacks
159 #
160 if [ ! -f $mbox ]
161 then
162         oldumask=`umask`
163         umask 077
164         touch $mbox
165         chmod 660 $mbox || exit 1
166         chown $user $mbox || exit 1
167         chgrp mail $mbox || exit 1
168         umask $oldumask
169 fi
170
171 # First lock the mailbox, if this doesn't succeed in 64 seconds, give up and
172 send
173 # mail to postmaster.
174 # If this period is to short, increase the retries (-r flag to lockfile)
175 #
176 # Then run the message through formail to get it into the right mailbox
177 format with the
178 # right headers added.
179 #
180 # Delivered-To will make fetchmail propagate this mail to the correct user
181 when
182 # run with '-E "Delivered-To"'. Set this in the advanced settings of the
183 TeamInternet f.i.
184 # (if you changed the envelope at the start of this script, adapt this
185 accordingly)
186 #
187 # We also muck up the messageid, so fetchmail will never skip a message on
188 the basis of
189 # duplicate messageIDs. The -i "Message-ID" will rename the old message ID,
190 the -a will
191 # add a new one.
192 #
193 # Lastly, we add a header indicating which host did the rewriting.
194 #
195
196 if lockfile -r 8 $mbox.lock >/dev/null 2>&1
197 then
198         cat - | formail -i "$envelope <$to>" -i "Message-ID:" -a
199 "Message-ID:" -i "X-Multidrop-Processing: <`hostname`>" >>$mbox
200         rm -f $mbox.lock
201 else
202         (echo "Subject: Cannot lock mailbox for $user" & cat -) |
203 /usr/lib/sendmail postmaster
204 fi
205
206 #
207 # EOF
208 #
209
210 This obviously is very Linux (even RedHat?) dependant, locking mailboxes,
211 creating mailboxes with the right permissions, probably even bash dependent.
212 I would say that it should be fairly easy to port to other systems, but
213 alas, my unix knowledge is lacking for that. I'll also rewrite it someday,
214 a.o. that umask handling can be done much better and the location of the
215 sendmail binairy should not be fixed.
216
217 Now the only thing left to do is to retrieve the mail with fetchmail, using
218 'envelope "Delivered-To:"' in the poll line. The above script has added this
219 line, so this is all that fetchmail needs.
220
221 All parts of this solution need carefull examination. In particular I think
222 the new rule lines may not catch all cases, although they worked for
223 everything I threw at them and work satisfactorily in production. I'm also
224 wondering if there is a more standard way to drop something in a mailbox. I
225 yet have to investigate procmail, but all other MDA's mucked with the
226 message and effectively undid my carefully added header. I'll experiment
227 some more and rethink it all as I learn more.
228
229 I'm still wondering, if I can get formail to include another received
230 line.... "Received from localhost by dropmail for <user>...." to make it
231 work without the envelope flag. Well I'll have to experiment. Do you know if
232 there is a header I can add so fetchmail works out-of-the-box?
233
234 Regards,
235 Martijn Lievaart
236