Add Debian directory
[mspang/vmailman.git] / debian / contrib / postfix-to-mailman.py
1 #! /usr/bin/env python
2
3 # $URL: svn+bsb://svn.winnegan.de/svn/adm/trunk/mailman/postfix-to-mailman.py $
4 # $Id: postfix-to-mailman.py 38 2004-04-15 19:11:32Z bsb $
5 #
6 # Interface mailman to a postfix with a mailman transport. Does not require
7 # the creation of _any_ aliases to connect lists to your mail system.
8 #
9 # Dax Kelson, dkelson@gurulabs.com, Sept 2002.
10 # coverted from qmail to postfix interface
11 # Jan 2003: Fixes for Mailman 2.1
12 # Thanks to Simen E. Sandberg <senilix@gallerbyen.net>
13 # Feb 2003: Change the suggested postfix transport to support VERP
14 # Thanks to Henrique de Moraes Holschuh <henrique.holschuh@ima.sp.gov.br>
15 #
16 # Mar 2004: Siggy Brentrup <bsb@debian.org>
17 #   downloaded from http://www.gurulabs.com/files/postfix-to-mailman-2.1.py
18 #   and adopted for inclusion in the Debian Mailman package.
19 #   (hi Bruce, back to the roots :-)
20 #   rewritten for python >= 2.2 taking configuration from mm_cfg
21 #
22 # This script was originally qmail-to-mailman.py by:
23 # Bruce Perens, bruce@perens.com, March 1999.
24 # This is free software under the GNU General Public License.
25
26 # This script is meant to be called as a postfix transport pipe.
27
28 # It catches all mail to a virtual domain, eg "lists.example.com".  It
29 # looks at the recipient for each mail message and decides if the mail
30 # is addressed to a valid list or not, and optionally bounces the
31 # message with a helpful suggestion if it's not addressed to a
32 # list. It decides if it is a posting, a list command, or mail to the
33 # list administrator, by checking for the -admin, -owner, -request,
34 # -join, -leave, -subscribe and -unsubscribe addresses. It will
35 # recognize a list as soon as the list is created, there is no need to
36 # add _any_ aliases for any list.  It recognizes mail to postmaster,
37 # abuse and mailer-daemon, and routes those mails to DEB_LISTMASTER as
38 # defined in mm_cfg.py
39
40 # INSTALLATION:
41 #
42 # Install this file as /var/lib/mailman/bin/postfix-to-mailman.py
43 #
44 # To configure a virtual domain to connect to mailman, edit Postfix thusly:
45 #
46 # /etc/postfix/main.cf:
47 #    relay_domains = ... lists.example.com
48 #    transport_maps = hash:/etc/postfix/transport
49 #    mailman_destination_recipient_limit = 1
50 #
51 # /etc/postfix/master.cf
52 #    mailman unix  -       n       n       -       -       pipe
53 #      flags=FR user=list 
54 #      argv=/var/lib/mailman/bin/postfix-to-mailman.py ${nexthop} ${mailbox}
55 #
56 # /etc/postfix/transport:
57 #   lists.example.com   mailman:
58 #
59 # /etc/mailman/mm_cfg.py
60 #    MTA = None # No MTA alias processing required
61 #    # alias for postmaster, abuse and mailer-daemon
62 #    DEB_LISTMASTER = 'postmaster@example.com'
63 #
64 # Replace lists.example.com above with the name of the domain to be
65 # connected to Mailman. Note that _all_ mail to that domain will go to
66 # Mailman, so you don't want to put the name of your main domain
67 # here. Typically a virtual domain lists.domain.com is used for
68 # Mailman, and domain.com for regular email.
69 #
70 # With the sheer amount of spam using faked addresses it seems more
71 # appropriate to me to just reject non-existing addresses.  The old
72 # behavior sending a helpful bounce message is still configurable
73 # by defining DEB_HELP_TEXT in mm_cfg.
74
75 # Exit codes accepted by postfix
76 #  from postfix-2.0.16/src/global/sys_exits.h
77 EX_USAGE    = 64    # command line usage error 
78 EX_NOUSER   = 67    # addressee unknown
79 EX_SOFTWARE = 70    # internal software error
80 EX_TEMPFAIL = 75    # temporary failure
81
82 import sys, os
83 sys.path.append("/usr/lib/mailman/bin")
84 import paths
85
86 from Mailman import mm_cfg
87
88 def main():
89     os.nice(5)     # Handle mailing lists at non-interactive priority.
90                    # delete this if you wish
91
92     try:
93         MailmanOwner = mm_cfg.DEB_LISTMASTER
94     except AttributeError:
95         MailmanOwner = 'postmaster@localhost'
96
97     try:
98         domain, local = [ a.lower() for a in sys.argv[1:] ]
99     except:
100         # This might happen if we're not using Postfix or
101         # /etc/postfix/master.cf is badly misconfigured
102         sys.stderr.write('Illegal invocation: %r\n'
103                          % ' '.join(sys.argv))
104         if len(sys.argv) > 3:
105             sys.stderr.write('Did you forget to set '
106                              'mailman_destination_recipient_limit=1 '
107                              'in main.cf?')
108         sys.exit(EX_USAGE)
109
110     # Redirect required addresses to 
111     if local in ('postmaster', 'abuse', 'mailer-daemon'):
112         os.execv("/usr/sbin/sendmail",
113                  ("/usr/sbin/sendmail", MailmanOwner))
114         sys.exit(0)
115
116     # Assume normal posting to a mailing list
117     mlist, func = local, 'post'
118
119     # Check for control extension on local part
120     for ext in ('-admin',
121                 '-owner',
122                 '-request',
123                 '-bounces',
124                 '-confirm',
125                 '-join',
126                 '-leave',
127                 '-subscribe',
128                 '-unsubscribe',
129                 ):
130         if local.endswith(ext):
131             mlist = local[:-len(ext)]
132             func  = ext[1:]
133             break
134
135     # Let Mailman decide if a list exists.
136     from Mailman.Utils import list_exists
137     if list_exists(mlist):
138         mm_pgm = os.path.join(paths.prefix, 'mail', 'mailman')
139         os.execv(mm_pgm, (mm_pgm, func, mlist))
140         # NOT REACHED
141     else:
142         try:
143             sys.stderr.write(mm_cfg.DEB_HELP_TEXT)
144         except AttributeError:
145             sys.exit(EX_NOUSER)
146
147         sys.exit(1)
148
149
150 if __name__ == '__main__':
151     try:
152         main()
153     except SystemExit, argument:
154         sys.exit(argument)
155     except Exception:
156         xt, xv, tb = sys.exc_info()
157         sys.stderr.write("%s %s\n" % (xt, xv))
158         sys.stderr.write("Line %d\n" % (tb.tb_lineno))
159         sys.exit(EX_TEMPFAIL) # Soft failure, try again later.