# Network Programming # Project 4 - File Mailer # import os import sys import stat import socket import smtplib from email.MIMEText import MIMEText from email.MIMEMultipart import MIMEMultipart from email.MIMEBase import MIMEBase from email import Utils, Encoders import mimetypes def attachment(filename): """ Add an attachment to a MIME Multipart message. Returns a MIME object. This function could be called from other code. It is called by the attach_file method of the FileMailer class """ fd = open(filename, 'rb') mimetype, mimeencoding = mimetypes.guess_type(filename) if mimeencoding or (mimetype is None): mimetype = 'application/octet-stream' maintype, subtype = mimetype.split('/') if maintype == 'text': retval = MIMEText(fd.read(), _subtype=subtype) else: retval = MIMEBase(maintype, subtype) retval.set_payload(fd.read()) Encoders.encode_base64(retval) retval.add_header('Content-Disposition', 'attachment', filename = filename) fd.close() return retval class FileMailer(object): """ Class to facilitate creating and sending e-mail messages with any number of MIME file attachments. It attempts to not send a message that is larger than what the server will accept. """ def __init__(self, server): """ Initialize the file mailer, check server for maximum message size """ # Get max message size of server # instatiate self.server here # set self.MaxSize and self.useesmtp # ADD CODE HERE # start with some size to allow for growth as other stuff is added. self.messageSize = 1024 self.full = False self.confirmedFiles = [] def attach_file(self, file_name): """ Checks for the existance and readability of a file and if the maximum message size is not exceeded, add the file to the list of files to be attached -- does not actually attach to the message that is done in send(). """ if not os.path.exists(file_name): return False if self.full: return False st = os.stat(file_name) mode = st[stat.ST_MODE] if not mode & stat.S_IREAD: return False # same as stat.S_IRUSR if self.useesmtp: fsize = st[stat.ST_SIZE] if self.messageSize + fsize > self.MaxSize: self.full = True return False else: self.messageSize += fsize self.confirmedFiles.append(file_name) return True def send(self, mailFrom, mailTo): """ Send the e-mail to mailTo list. It creates the message body with the names of the files attached. Then it attaches the files and sends the message checking for errors. It returns the number of files that were attached prior to sending. """ # ADD YOUR CODE HERE # 1. Create a mime multipart object # 2. Add the headers. Subject should report the number of files # attached. To, From, Subject, Date, Message-ID # 3. Create and attach the message body containing a list of files # attached. # 4. Attach all the files. # 5. Send the message checking for errors. # 6. Return the number of files attached. def mail_files(server, mail_from, mail_to, filelist): """ A wrapper function for the FileMailer class, it attaches the files from the filelist list and sends the message. mail_from is a string. mail_to is a list of strings containing e-mail addresses. It returns the number of files attached. """ fMailer = FileMailer(server) if fMailer is None: return 0 for filename in filelist: if not fMailer.attach_file(filename): print "%s not attached" % filename return fMailer.send(mail_from, mail_to) if __name__ == "__main__": # test the file mailer server = 'localhost:8025' #server = 'smtp.central.cox.net' # feel free to change mailTo to your addresses. mailTo = ['you@ksu.edu', 'you@sal.ksu.edu'] files = [ 'foo.txt', 'foo.zip', 'foo.jpg', 'nothere.txt' ] # expect to see an error for last file nfiles = mail_files(server, 'from_you@gmail.com', mailTo, files) print "%d files were mailed to %d recipients" % (nfiles, len(mailTo))