usr bin python Justin Quick 02-2008 justquick gmail com Copyright 2007

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#!/usr/bin/python
# Justin Quick 02-2008 justquick@gmail.com
# Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
# Everyone is permitted to copy and distribute verbatim copies
# of this license document, but changing it is not allowed. see LICENSE
import sys,smtplib,MimeWriter,base64,StringIO,os,mimetypes,optparse,getpass,re,socket
# ip,domain and dns helpers
def getdomain(hostname): return '.'.join(hostname.split('.')[1:])
def likeip(astr):
return re.compile('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}').match(astr)
def getmx(domain):
# Returns highest priority server from mx search
capture,servers = 0,[]
for l in os.popen('dig %s mx'%domain):
l=l.strip()
if l==';; ANSWER SECTION:': capture = 1
elif l=='': capture = 0
elif capture:
a,b = l.split('\t')[-1].split(' ')
servers.append((int(a),b[:-1]))
servers.sort(lambda x,y: cmp(x[0],y[0]))
return servers[0][1]
# argument parser
desc = """MimeMail: Simple smtp client able to send mime messages which allows for: html body (from input or file), attachments, bcc/cc. It can also dig through a domain and retrieve the highest priority server from an mx search."""
parser = optparse.OptionParser(description=desc,
usage='%prog [<username>@<domain>|<username> <servername>]')
parser.add_option('-p',"--password", action='store_true',dest="passwd",
default=False,help="authenticate user, prompting for password")
parser.add_option("--key", dest="key",default='',help="the TLS keyfile")
parser.add_option("--cert", dest="cert",default='',help="the TLS certfile")
(options, args) = parser.parse_args()
# get username, smtp server hostname and domain for connection
if args and args[0].find('@')!=-1:
user,domain = args[0].split('@')
server = getmx(domain)
elif args and len(args)==2:
user,server = args
if likeip(server): server = socket.gethostbyaddr(server)[0]
domain = getdomain(server)
else:
print parser.format_help()
sys.exit()
# create connection
try: smtp = smtplib.SMTP(server)#; smtp.set_debuglevel(1)
except: raise 'Connection error with %s'%server
# login and check credentials
if options.passwd:
try: smtp.login(user,getpass.getpass('Password for %s@%s: '%(user,domain)))
except: raise 'Credentials error with %s on %s'%(user,server)
# start Transport Layer Security mode if keyfile and certfile
if options.key and options.cert:
smtp.starttls(options.key,options.cert)
smtp.helo()
# interface for writing MIME email messages
subject,body,to,bcc,cc,attchs = '','',[],[],[],[]
def prompt(prompt): return raw_input(prompt).strip()
def sub(c):
# subfunction handler
global server,port,subject,body,to,bcc,cc,attchs
try: c = int(c)
except: return
if c==1:
print 'New HTML body content:\n'
body = ''
while 1:
try: data = raw_input()
except EOFError: break
if not data: break
body += data
elif c==2:
body = open(prompt('Filename: ')).read()
elif c==3: subject = prompt('New subject: ')
elif c==4: to = prompt('Email addresses (comma sep): ').split(',')
elif c==5:
fi = prompt('Filename: ')
if not os.path.isfile(fi):
raise IOError, 'File %s not found!'%fi
attchs.append(fi)
elif c==6:
bcc = prompt('BCCs (comma sep): ').split(',')
cc = prompt('CCs (comma sep): ').split(',')
elif c==7: return c
# interface
print """Connected. Now compose message:
\t1. New message body
\t2. Load message body from file
\t3. Subject
\t4. To addresses
\t5. Add Attachment
\t6. Set BCC/CC
\t7. Send"""
while 1:
try: cmd = prompt("smtp> ")
except: print '\nExiting'; sys.exit()
if sub(cmd): break
# Init mime message with necessary headers
message = StringIO.StringIO()
writer = MimeWriter.MimeWriter(message)
writer.addheader('Subject', subject)
for addr in to: writer.addheader('To', addr)
for addr in cc: writer.addheader('Cc', addr)
for addr in bcc: writer.addheader('Bcc', addr)
writer.startmultipartbody('mixed')
# add body
part = writer.nextpart()
bod = part.startbody('text/html')
bod.write(body)
# add attachments
for attch in attchs:
part = writer.nextpart()
part.addheader('Content-Transfer-Encoding', 'base64')
part.addheader("Content-Disposition",
'attachment; filename="%s"'%os.path.basename(attch))
mime = mimetypes.guess_type(attch)[0]
if not mime: mime = 'text/plain'
base64.encode(open(attch,'rb'),part.startbody(mime))
# send the mail
writer.lastpart()
errors = smtp.sendmail('%s@%s'%(user,domain), to, message.getvalue())
# catch errrors
if not errors: print 'Email sent sucessfully'
else:
for k,v in errors.items(): print 'Error with address %s: %s'%(k,v)
# close connection before exiting
smtp.quit()