#!/usr/bin/env python ''' a module wrapping smtplib, mimetypes, and the email modules into a single function for sending emails with any kind of attachments. when run as a script, it functions a bit like the unix command /bin/mail: $ echo "like satan!" | python send_email.py from me@here.com to faulkner@users.sf.net re "you rock!" attach if 'attach' is the last argument [as in above], it will open a Tkinter file dialog. else if there are arguments after 'attach' and before any other keywords, it will treat those arguments as all the filenames to attach. ''' import os, sys, smtplib, mimetypes, email.MIMEMultipart, email.MIMEText, email.MIMEImage, email.MIMEAudio, email.MIMEBase, email.Message def send_email(body, subject, from_whom, to_whom, smtp_server='smtp.olin.edu', attachment_filenames=()): ''' all arguments must be str's/unicode's except attachment_filenames, which must be a list/tuple of str filenames, and to_whom, which can also be a list/tuple of str addresses, or a semicolon-separated str of addresses. lets socket.gaierror through if smtp_server is not actually an smtp server, or to_whom/from_whom aren't actually addresses. based on something on aspn. ''' if isinstance(to_whom, (str, unicode)): to_whom = to_whom.split(';') elif not (isinstance(to_whom, (list, tuple)) and all([isinstance(x, (str, unicode)) for x in to_whom]) ): raise TypeError('to_whom must be either str/unicode, or list/tuple of strs/unicodes') smtp = smtplib.SMTP(smtp_server) outer = email.MIMEMultipart.MIMEMultipart() outer['Subject'] = subject outer['To'] = ', '.join(to_whom) outer['From'] = from_whom outer.preamble = 'get a MIME-aware email client, like thunderbird.' outer.epilogue = '' # To guarantee the message ends with a newline outer.attach(email.MIMEText.MIMEText(body)) for path in attachment_filenames: ctype, encoding = mimetypes.guess_type(path) if ctype is None or encoding is not None: # No guess could be made, or the file is encoded (compressed), so # use a generic bag-of-bits type. ctype = 'application/octet-stream' maintype, subtype = ctype.split('/', 1) if maintype == 'text': fp = open(path) msg = email.MIMEText.MIMEText(fp.read(), _subtype=subtype) fp.close() elif maintype == 'image': fp = open(path, 'rb') msg = email.MIMEImage.MIMEImage(fp.read(), _subtype=subtype) fp.close() elif maintype == 'audio': fp = open(path, 'rb') msg = email.MIMEAudio.MIMEAudio(fp.read(), _subtype=subtype) fp.close() else: fp = open(path, 'rb') msg = email.MIMEBase.MIMEBase(maintype, subtype) msg.set_payload(fp.read()) fp.close() email.Encoders.encode_base64(msg) msg.add_header('Content-Disposition', 'attachment', filename=os.path.basename(path)) outer.attach(msg) smtp.sendmail(from_whom, to_whom, outer.as_string()) smtp.quit() def main(argv): ''' main(['from', 'me@here.com', 'to', 'faulkner@users.sf.net', 're', 'Lython', 'attach']) ''' if 'from' in argv: from_whom = argv[argv.index('from') + 1] argv.remove('from') argv.remove(from_whom) else: from_whom = raw_input('from whom? ') if 'to' in argv: to_whom = argv[argv.index('to') + 1] argv.remove('to') argv.remove('to_whom') else: to_whom = raw_input('to whom? ') if 're' in argv: subject = argv[argv.index('re') + 1] argv.remove('re') argv.remove(subject) else: subject = raw_input('subject? ') if 'attach' in argv: i = argv.index('attach') if i == len(argv) - 1: from tkFileDialog import askopenfilenames attachment_filenames = askopenfilenames() else: attachment_filenames = argv[i + 1 :] argv = argv[:i] elif 'y' in raw_input('\n\ndo you want to attach any files? [y|N] '): from tkFileDialog import askopenfilenames attachment_filenames = askopenfilenames() else: attachment_filenames = [] body = sys.stdin.read() # until EOF [control + D] send_email(body, subject, from_whom, to_whom, attachment_filenames=attachment_filenames) if __name__ == '__main__': sys.exit(main(sys.argv[1:]))