#!/usr/bin/python import csv import email.parser from optparse import OptionParser import os import smtplib import subprocess import sys sender_header = 'mail-merge-sender@mit.edu' rtkit_path = '/afs/athena.mit.edu/user/a/d/adehnert/arch/common/lib/python/' smtp = None def dictize_line(header, line,): line_dict = {} for key, elem in zip(header, line, ): line_dict[key]=elem return line_dict def setup_sendmail_smtp(): global smtp smtp = smtplib.SMTP() smtp.connect() def sendmail_smtp(addrs, text): global smtp smtp.sendmail(sender_header, addrs, text, ) smtp_funcs = (setup_sendmail_smtp, sendmail_smtp, ) def sendmail_cmd(addrs, text): args = ["/usr/lib/sendmail", "--", ] args.extend(addrs) proc = subprocess.Popen(args, stdin=subprocess.PIPE) proc.communicate(text) if proc.returncode != 0: raise RuntimeError, "sendmail returned %d" % (proc.returncode, ) cmd_funcs = (lambda: True, sendmail_cmd) setup_sendmail, sendmail = smtp_funcs setup_sendmail, sendmail = cmd_funcs def parse_arguments(): parser = OptionParser(usage='usage: %prog [options] cc_addr template recipients') parser.add_option('-q', '--rt-queue', dest='rt_queue', help='Automatically create a ticket in queue QUEUE', metavar='QUEUE', ) parser.add_option('-o', '--rt-owner', dest='rt_owner', help='Set RT owner and AdminCC to USER', metavar='USER', ) parser.add_option('--split', dest='split', help='Split "email" field on SPLIT and send to each recipient', metavar='SPLIT', ) (options, args) = parser.parse_args() if len(args) != 3: parser.error("incorrect number of arguments") if options.rt_owner and not options.rt_queue: parser.error("--rt-owner requires specifying a queue") return options, args def nop_msg_filter(rcpts, body): return rcpts, body def msg_filter_factory(opts): if not opts.rt_queue: return nop_msg_filter try: import rtkit.tracker, rtkit.authenticators, rtkit.errors except ImportError: print "Note: using rtkit from %s" % (rtkit_path, ) sys.path.append(rtkit_path) import rtkit.tracker, rtkit.authenticators, rtkit.errors cookie = rtkit.authenticators.CookieAuthenticator resource = rtkit.resource.RTResource.from_rtrc(cookie) parser = email.parser.Parser() def filter_rt(rcpts, body, ): msg = parser.parsestr(body) content = { 'content': { 'Requestors': ", ".join(rcpts), 'Queue': opts.rt_queue, 'Subject' : msg['Subject'], 'Text' : '', } } if opts.rt_owner: content['content']['AdminCC'] = opts.rt_owner content['content']['Owner'] = opts.rt_owner try: response = resource.post(path='ticket/new', payload=content,) results = dict(response.parsed[0]) ticket, ticket_number = results['id'].split('/') assert ticket == 'ticket', 'unexpected value "%s" instead of ticket' % (ticket, ) subject = "%s [help.mit.edu #%s]" % (msg['Subject'], ticket_number) del msg['Subject'] msg['Subject'] = subject except rtkit.errors.RTResourceError as e: logger.error(e.response.status_int) logger.error(e.response.status) logger.error(e.response.parsed) # We don't want to send mail to the real recipient, because RT # will send them a copy too. return [], msg.as_string() return filter_rt def mail_merge(opts, cc_addr, email_file, recipients_file): email_tmpl = open(email_file, 'rU').read() reader = csv.reader(open(recipients_file, 'rU')) header = reader.next() msg_filter = msg_filter_factory(opts) print header if not 'email' in header: print >>sys.stderr, "Your CSV file doesn't have an email field. You should fix that.\n(Note that this script is case-sensitive.)" return False for line in reader: dct = dictize_line(header, line, ) print dct text = email_tmpl % dct if opts.split: prop_rcpts = dct['email'].split(opts.split) else: prop_rcpts = [dct['email']] rcpts, text = msg_filter(prop_rcpts, text, ) rcpts.append(cc_addr) sendmail(rcpts, text, ) if __name__=='__main__': options, args = parse_arguments() setup_sendmail() mail_merge(options, *args)