mail-merge: only send one copy with RT
[user/alex/software/my-snippets.git] / mail-merge
1 #!/usr/bin/python
2
3 import csv
4 import email.parser
5 from optparse import OptionParser
6 import os
7 import smtplib
8 import subprocess
9 import sys
10
11
12 sender_header = 'mail-merge-sender@mit.edu'
13 smtp = None
14
15 def dictize_line(header, line,):
16     line_dict = {}
17     for key, elem in zip(header, line, ):
18         line_dict[key]=elem
19     return line_dict
20
21 def setup_sendmail_smtp():
22     global smtp
23     smtp = smtplib.SMTP()
24     smtp.connect()
25 def sendmail_smtp(addrs, text):
26     global smtp
27     smtp.sendmail(sender_header, addrs, text, )
28 smtp_funcs = (setup_sendmail_smtp, sendmail_smtp, )
29
30 def sendmail_cmd(addrs, text):
31     args = ["/usr/lib/sendmail", "--", ]
32     args.extend(addrs)
33     proc = subprocess.Popen(args, stdin=subprocess.PIPE)
34     proc.communicate(text)
35 cmd_funcs = (lambda: True, sendmail_cmd)
36
37 setup_sendmail, sendmail = smtp_funcs
38 setup_sendmail, sendmail = cmd_funcs
39
40 def parse_arguments():
41     parser = OptionParser(usage='usage: %prog [options] cc_addr template recipients')
42     parser.add_option('-q', '--rt-queue', dest='rt_queue',
43             help='Automatically create a ticket in queue QUEUE',
44             metavar='QUEUE',
45     )
46     parser.add_option('-o', '--rt-owner', dest='rt_owner',
47             help='Set RT owner and AdminCC to USER',
48             metavar='USER',
49     )
50     (options, args) = parser.parse_args()
51     if len(args) != 3:
52         parser.error("incorrect number of arguments")
53     if options.rt_owner and not options.rt_queue:
54         parser.error("--rt-owner requires specifying a queue")
55     return options, args
56
57 def nop_msg_filter(rcpt, body):
58     return rcpt, body
59
60 def msg_filter_factory(opts):
61     if not opts.rt_queue:
62         return nop_msg_filter
63
64     import rtkit.tracker, rtkit.authenticators, rtkit.errors
65     cookie = rtkit.authenticators.CookieAuthenticator
66     resource = rtkit.resource.RTResource.from_rtrc(cookie)
67     parser = email.parser.Parser()
68
69     def filter_rt(rcpt, body, ):
70         msg = parser.parsestr(body)
71         content = {
72             'content': {
73                 'Requestors': rcpt,
74                 'Queue': opts.rt_queue,
75                 'Subject' : msg['Subject'],
76                 'Text' : '',
77             }
78         }
79         if opts.rt_owner:
80             content['content']['AdminCC'] = opts.rt_owner
81             content['content']['Owner'] = opts.rt_owner
82
83         try:
84             response = resource.post(path='ticket/new', payload=content,)
85             results = dict(response.parsed[0])
86             ticket, ticket_number = results['id'].split('/')
87             assert ticket == 'ticket', 'unexpected value "%s" instead of ticket' % (ticket, )
88             subject = "%s [help.mit.edu #%s]" % (msg['Subject'], ticket_number)
89             del msg['Subject']
90             msg['Subject'] = subject
91         except rtkit.errors.RTResourceError as e:
92             logger.error(e.response.status_int)
93             logger.error(e.response.status)
94             logger.error(e.response.parsed)
95
96         # We don't want to send mail to the real recipient, because RT
97         # will send them a copy too.
98         return None, msg.as_string()
99
100     return filter_rt
101
102 def mail_merge(opts, cc_addr, email_file, recipients_file):
103     email_tmpl = open(email_file, 'r').read()
104     reader = csv.reader(open(recipients_file, 'r'))
105     header = reader.next()
106     msg_filter = msg_filter_factory(opts)
107     print header
108     for line in reader:
109         dct = dictize_line(header, line, )
110         print dct
111         text = email_tmpl % dct
112         rcpt, text = msg_filter(dct['email'], text, )
113         rcpts = [cc_addr]
114         if rcpt:
115             rcpts.append(rcpt)
116         sendmail(rcpts, text, )
117
118 if __name__=='__main__':
119     options, args = parse_arguments()
120     setup_sendmail()
121     mail_merge(options, *args)