5 from optparse import OptionParser
12 sender_header = 'mail-merge-sender@mit.edu'
13 rtkit_path = '/afs/athena.mit.edu/user/a/d/adehnert/arch/common/lib/python/'
16 def dictize_line(header, line,):
18 for key, elem in zip(header, line, ):
22 def setup_sendmail_smtp():
26 def sendmail_smtp(addrs, text):
28 smtp.sendmail(sender_header, addrs, text, )
29 smtp_funcs = (setup_sendmail_smtp, sendmail_smtp, )
31 def sendmail_cmd(addrs, text):
32 args = ["/usr/lib/sendmail", "--", ]
34 proc = subprocess.Popen(args, stdin=subprocess.PIPE)
35 proc.communicate(text)
36 if proc.returncode != 0:
37 raise RuntimeError, "sendmail returned %d" % (proc.returncode, )
38 cmd_funcs = (lambda: True, sendmail_cmd)
40 setup_sendmail, sendmail = smtp_funcs
41 setup_sendmail, sendmail = cmd_funcs
43 def parse_arguments():
44 parser = OptionParser(usage='usage: %prog [options] cc_addr template recipients')
45 parser.add_option('-q', '--rt-queue', dest='rt_queue',
46 help='Automatically create a ticket in queue QUEUE',
49 parser.add_option('-o', '--rt-owner', dest='rt_owner',
50 help='Set RT owner and AdminCC to USER',
53 parser.add_option('--split', dest='split',
54 help='Split "email" field on SPLIT and send to each recipient',
57 (options, args) = parser.parse_args()
59 parser.error("incorrect number of arguments")
60 if options.rt_owner and not options.rt_queue:
61 parser.error("--rt-owner requires specifying a queue")
64 def nop_msg_filter(rcpts, body):
67 def msg_filter_factory(opts):
72 import rtkit.tracker, rtkit.authenticators, rtkit.errors
74 print "Note: using rtkit from %s" % (rtkit_path, )
75 sys.path.append(rtkit_path)
76 import rtkit.tracker, rtkit.authenticators, rtkit.errors
78 cookie = rtkit.authenticators.CookieAuthenticator
79 resource = rtkit.resource.RTResource.from_rtrc(cookie)
80 parser = email.parser.Parser()
82 def filter_rt(rcpts, body, ):
83 msg = parser.parsestr(body)
86 'Requestors': ", ".join(rcpts),
87 'Queue': opts.rt_queue,
88 'Subject' : msg['Subject'],
93 content['content']['AdminCC'] = opts.rt_owner
94 content['content']['Owner'] = opts.rt_owner
97 response = resource.post(path='ticket/new', payload=content,)
98 results = dict(response.parsed[0])
99 ticket, ticket_number = results['id'].split('/')
100 assert ticket == 'ticket', 'unexpected value "%s" instead of ticket' % (ticket, )
101 subject = "%s [help.mit.edu #%s]" % (msg['Subject'], ticket_number)
103 msg['Subject'] = subject
104 except rtkit.errors.RTResourceError as e:
105 logger.error(e.response.status_int)
106 logger.error(e.response.status)
107 logger.error(e.response.parsed)
109 # We don't want to send mail to the real recipient, because RT
110 # will send them a copy too.
111 return [], msg.as_string()
115 def mail_merge(opts, cc_addr, email_file, recipients_file):
116 email_tmpl = open(email_file, 'rU').read()
117 reader = csv.reader(open(recipients_file, 'rU'))
118 header = reader.next()
119 msg_filter = msg_filter_factory(opts)
121 if not 'email' in header:
122 print >>sys.stderr, "Your CSV file doesn't have an email field. You should fix that.\n(Note that this script is case-sensitive.)"
125 dct = dictize_line(header, line, )
127 text = email_tmpl % dct
129 prop_rcpts = dct['email'].split(opts.split)
131 prop_rcpts = [dct['email']]
132 rcpts, text = msg_filter(prop_rcpts, text, )
133 rcpts.append(cc_addr)
134 sendmail(rcpts, text, )
136 if __name__=='__main__':
137 options, args = parse_arguments()
139 mail_merge(options, *args)