5 from optparse import OptionParser
12 sender_header = 'mail-merge-sender@mit.edu'
15 def dictize_line(header, line,):
17 for key, elem in zip(header, line, ):
21 def setup_sendmail_smtp():
25 def sendmail_smtp(addrs, text):
27 smtp.sendmail(sender_header, addrs, text, )
28 smtp_funcs = (setup_sendmail_smtp, sendmail_smtp, )
30 def sendmail_cmd(addrs, text):
31 args = ["/usr/lib/sendmail", "--", ]
33 proc = subprocess.Popen(args, stdin=subprocess.PIPE)
34 proc.communicate(text)
35 cmd_funcs = (lambda: True, sendmail_cmd)
37 setup_sendmail, sendmail = smtp_funcs
38 setup_sendmail, sendmail = cmd_funcs
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',
46 parser.add_option('-o', '--rt-owner', dest='rt_owner',
47 help='Set RT owner and AdminCC to USER',
50 (options, args) = parser.parse_args()
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")
57 def nop_msg_filter(rcpt, body):
60 def msg_filter_factory(opts):
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()
69 def filter_rt(rcpt, body, ):
70 msg = parser.parsestr(body)
74 'Queue': opts.rt_queue,
75 'Subject' : msg['Subject'],
80 content['content']['AdminCC'] = opts.rt_owner
81 content['content']['Owner'] = opts.rt_owner
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)
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)
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()
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)
109 dct = dictize_line(header, line, )
111 text = email_tmpl % dct
112 rcpt, text = msg_filter(dct['email'], text, )
116 sendmail(rcpts, text, )
118 if __name__=='__main__':
119 options, args = parse_arguments()
121 mail_merge(options, *args)