| 1 |
|
|---|
| 2 |
|
|---|
| 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 |
|
|---|
| 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 |
|
|---|
| 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 |
|
|---|
| 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 |
|
|---|
| 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 |
|
|---|
| 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 |
|
|---|
| 126 |
|
|---|
| 127 |
sys.exit(0) |
|---|