## 12.2.13 Examples

Here are a few examples of how to use the `email` package to read, write, and send simple email messages, as well as more complex MIME messages.

First, let's see how to create and send a simple text message:

      # 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()

Here's an example of how to send a MIME message containing a bunch of family pictures that may be residing in a directory:

      # 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()

Here's an example of how to send the entire contents of a directory as an email message: 12.4

      #!/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.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()

And finally, here's an example of how to unpack a MIME message like the one above, into a directory of files:

      #!/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()

#### Footnotes

... message:12.4
  Thanks to Matthew Dixon Cowles for the original inspiration and examples.