ここでは email パッケージを使って電子メールメッセージを 読む・書く・送信するいくつかの例を紹介します。より複雑な MIME メッセージについても扱います。
最初に、テキスト形式の単純なメッセージを作成・送信する方法です:
# Import smtplib for the actual sending function import smtplib # Import the email modules we'll need from email.MIMEText import MIMEText # Open a plain text file for reading. For this example, assume that # the text file contains only ASCII characters. fp = open(textfile, 'rb') # Create a text/plain message msg = MIMEText(fp.read()) fp.close() # me == the sender's email address # you == the recipient's email address msg['Subject'] = 'The contents of %s' % textfile msg['From'] = me msg['To'] = you # Send the message via our own SMTP server, but don't include the # envelope header. s = smtplib.SMTP() s.connect() s.sendmail(me, [you], msg.as_string()) s.close()
つぎに、あるディレクトリ内にある何枚かの家族写真をひとつの MIME メッセージに 収めて送信する例です:
# Import smtplib for the actual sending function import smtplib # Here are the email pacakge modules we'll need from email.MIMEImage import MIMEImage from email.MIMEMultipart import MIMEMultipart COMMASPACE = ', ' # Create the container (outer) email message. msg = MIMEMultipart() msg['Subject'] = 'Our family reunion' # me == the sender's email address # family = the list of all recipients' email addresses msg['From'] = me msg['To'] = COMMASPACE.join(family) msg.preamble = 'Our family reunion' # Guarantees the message ends in a newline msg.epilogue = '' # Assume we know that the image files are all in PNG format for file in pngfiles: # Open the files in binary mode. Let the MIMEImage class automatically # guess the specific image type. fp = open(file, 'rb') img = MIMEImage(fp.read()) fp.close() msg.attach(img) # Send the email via our own SMTP server. s = smtplib.SMTP() s.connect() s.sendmail(me, family, msg.as_string()) s.close()
つぎはあるディレクトリに含まれている内容全体を ひとつの電子メールメッセージとして送信するやり方です 12.9:
#!/usr/bin/env python """Send the contents of a directory as a MIME message. Usage: dirmail [options] from to [to ...]* Options: -h / --help Print this message and exit. -d directory --directory=directory Mail the contents of the specified directory, otherwise use the current directory. Only the regular files in the directory are sent, and we don't recurse to subdirectories. `from' is the email address of the sender of the message. `to' is the email address of the recipient of the message, and multiple recipients may be given. The email is sent by forwarding to your local SMTP server, which then does the normal delivery process. Your local machine must be running an SMTP server. """ import sys import os import getopt import smtplib # For guessing MIME type based on file name extension import mimetypes from email import Encoders from email.Message import Message from email.MIMEAudio import MIMEAudio from email.MIMEBase import MIMEBase from email.MIMEMultipart import MIMEMultipart from email.MIMEImage import MIMEImage from email.MIMEText import MIMEText COMMASPACE = ', ' def usage(code, msg=''): print >> sys.stderr, __doc__ if msg: print >> sys.stderr, msg sys.exit(code) def main(): try: opts, args = getopt.getopt(sys.argv[1:], 'hd:', ['help', 'directory=']) except getopt.error, msg: usage(1, msg) dir = os.curdir for opt, arg in opts: if opt in ('-h', '--help'): usage(0) elif opt in ('-d', '--directory'): dir = arg if len(args) < 2: usage(1) sender = args[0] recips = args[1:] # Create the enclosing (outer) message outer = MIMEMultipart() outer['Subject'] = 'Contents of directory %s' % os.path.abspath(dir) outer['To'] = COMMASPACE.join(recips) outer['From'] = sender outer.preamble = 'You will not see this in a MIME-aware mail reader.\n' # To guarantee the message ends with a newline outer.epilogue = '' for filename in os.listdir(dir): path = os.path.join(dir, filename) if not os.path.isfile(path): continue # Guess the content type based on the file's extension. Encoding # will be ignored, although we should check for simple things like # gzip'd or compressed files. 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) # Note: we should handle calculating the charset msg = MIMEText(fp.read(), _subtype=subtype) fp.close() elif maintype == 'image': fp = open(path, 'rb') msg = MIMEImage(fp.read(), _subtype=subtype) fp.close() elif maintype == 'audio': fp = open(path, 'rb') msg = MIMEAudio(fp.read(), _subtype=subtype) fp.close() else: fp = open(path, 'rb') msg = MIMEBase(maintype, subtype) msg.set_payload(fp.read()) fp.close() # Encode the payload using Base64 Encoders.encode_base64(msg) # Set the filename parameter msg.add_header('Content-Disposition', 'attachment', filename=filename) outer.attach(msg) # Now send the message s = smtplib.SMTP() s.connect() s.sendmail(sender, recips, outer.as_string()) s.close() if __name__ == '__main__': main()
そして最後に、上のような MIME メッセージをどうやって 展開してひとつのディレクトリ上の複数ファイルにするかを示します:
#!/usr/bin/env python """Unpack a MIME message into a directory of files. Usage: unpackmail [options] msgfile Options: -h / --help Print this message and exit. -d directory --directory=directory Unpack the MIME message into the named directory, which will be created if it doesn't already exist. msgfile is the path to the file containing the MIME message. """ import sys import os import getopt import errno import mimetypes import email def usage(code, msg=''): print >> sys.stderr, __doc__ if msg: print >> sys.stderr, msg sys.exit(code) def main(): try: opts, args = getopt.getopt(sys.argv[1:], 'hd:', ['help', 'directory=']) except getopt.error, msg: usage(1, msg) dir = os.curdir for opt, arg in opts: if opt in ('-h', '--help'): usage(0) elif opt in ('-d', '--directory'): dir = arg try: msgfile = args[0] except IndexError: usage(1) try: os.mkdir(dir) except OSError, e: # Ignore directory exists error if e.errno <> errno.EEXIST: raise fp = open(msgfile) msg = email.message_from_file(fp) fp.close() counter = 1 for part in msg.walk(): # multipart/* are just containers if part.get_content_maintype() == 'multipart': continue # Applications should really sanitize the given filename so that an # email message can't be used to overwrite important files filename = part.get_filename() if not filename: ext = mimetypes.guess_extension(part.get_type()) if not ext: # Use a generic bag-of-bits extension ext = '.bin' filename = 'part-%03d%s' % (counter, ext) counter += 1 fp = open(os.path.join(dir, filename), 'wb') fp.write(part.get_payload(decode=1)) fp.close() if __name__ == '__main__': main()