root/python/ml/ml.py

リビジョン 46, 3.2 kB (コミッタ: sgk, コミット時期: 11 ヶ月 前)

メーリングリスト

  • svn:executable 属性の設定値: *
Line 
1 #!/usr/bin/python
2 #vim:fileencoding=utf-8
3
4 '''
5 ml.py -- simple mailing list to just distribute messages in a group.
6
7 Copyright (c) 2007 Shigeru KANEMOTO
8 All rights reserved.
9 '''
10
11 LIST_ADDRESS = 'list@example.com'
12 LIST_SUBSCRIBERS = {
13   # 'email address (lower case)': u'real name',
14   'somebody@example.com': u'なまえ',
15 }
16
17 import sys
18 import re
19 import email.FeedParser
20 import email.Header
21 import email.Utils
22 import smtplib
23
24 BUFFER_SIZE = 1024
25
26
27 class MLError(RuntimeError):
28   pass
29
30
31 def message_from_fileobj(fileobj):
32   parser = email.FeedParser.FeedParser()
33   while True:
34     buffer = fileobj.read(BUFFER_SIZE)
35     if not buffer:
36       return parser.close()
37     parser.feed(buffer)
38
39
40 def alter_message_for_forwarding(message):
41   # Check the destination
42   recipients = message.get_all('to', [])
43   recipients += message.get_all('cc', [])
44   recipients += message.get_all('resent-to', [])
45   recipients += message.get_all('resent-cc', [])
46   recipients = email.Utils.getaddresses(recipients)
47   for (realname, address) in recipients:
48     if address.lower() == LIST_ADDRESS:
49       break
50   else:
51     raise MLError, 'Not sent to this list.'
52
53   # Get nickname of the sender
54   sender = message['from']
55   if not sender:
56     raise MLError, 'No "from" header found.'
57   (realname, sender) = email.Utils.parseaddr(sender)
58   if not sender:
59     raise MLError, '"from" header not recognized.'
60   sender = sender.lower()
61   try:
62     nickname = LIST_SUBSCRIBERS[sender]
63   except KeyError:
64     raise MLError, 'Sender "%s" not allowed.' % sender
65
66   # Get the subject
67   subject = message.get('subject', '')
68   subject = email.Header.decode_header(subject)
69   (s, charset) = subject[0]
70   s = re.sub(r'^(Re|RE|re)(\d*|\[\d+\])[:>]\s*(Bcc:\s*|)', '', s, 1)
71   subject[0] = (s, charset)
72   subject = email.Header.make_header(subject)
73
74   # Prepare the new message
75   del message['to']
76   del message['cc']
77   del message['resent-to']
78   del message['resent-cc']
79   del message['from']
80   del message['reply-to']
81   del message['subject']
82   message['To'] = LIST_ADDRESS
83   message['From'] = LIST_ADDRESS
84   message['Subject'] = subject
85
86   def insert_nickname(m):
87     if m.get_content_maintype() != 'text':
88       return
89     charset = m.get_content_charset()
90     body = m.get_payload()
91     if charset:
92       body = body.decode(charset)
93     if m.get_content_subtype() == 'html':
94       body = re.sub(r'^(.*<(body|BODY).*>|)', r'\1[%s]<br />' % nickname, body, 1)
95     else:
96       body = ('[%s]\r\n' % nickname) + body
97     if charset:
98       body = body.encode(charset)
99     m.set_payload(body)
100
101   if message.is_multipart():
102     for m in message.get_payload():
103       insert_nickname(m)
104   else:
105     insert_nickname(message)
106
107   return sender
108
109
110 def deliver_message(sender, message):
111   recipients = LIST_SUBSCRIBERS.keys()
112   recipients.remove(sender)
113   smtp = smtplib.SMTP('localhost')
114   smtp.sendmail(LIST_ADDRESS, recipients, message.as_string())
115   smtp.close()
116
117
118 if __name__ == '__main__':
119   try:
120     message = message_from_fileobj(sys.stdin)
121     sender = alter_message_for_forwarding(message)
122     deliver_message(sender, message)
123   except MLError, e:
124     print >>sys.stderr, str(e)
125     # Courier suspends delivery to same address for a while after exiting
126     # with exit code except zero.
127     sys.exit(0)
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。