ActiveState Code

Recipe 86674: Use email module to bundle contents of current directory


An example of using the email module to create a multipart MIME message.

Python
 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
#!/usr/bin/env python

import cStringIO
import base64
import email.Message
import email.Utils
import mimetypes
import os
import quopri

toAddr="example@example.com"
fromAddr="example@example.com"
outputFile="dirContentsMail"

def main():
  mainMsg=email.Message.Message()
  mainMsg["To"]=toAddr
  mainMsg["From"]=fromAddr
  mainMsg["Subject"]="Directory contents"
  mainMsg["Date"]=email.Utils.formatdate(localtime=1)
  mainMsg["Message-ID"]=email.Utils.make_msgid()
  mainMsg["Mime-version"]="1.0"
  mainMsg["Content-type"]="Multipart/mixed"
  mainMsg.preamble="Mime message\n"
  mainMsg.epilogue="" # To ensure that message ends with newline
  
  firstSubMsg=email.Message.Message()
  firstSubMsg["Content-type"]="text/plain"
  firstSubMsg["Content-transfer-encoding"]="7bit"
  firstSubMsg.set_payload("Files from directory\n")
  mainMsg.attach(firstSubMsg)
  
  # Get names of plain files
  fileNames=[f for f in os.listdir(os.curdir) if os.path.isfile(f)]
  for fileName in fileNames:
    contentType,ignored=mimetypes.guess_type(fileName)
    if contentType==None: # If no guess, use generic opaque type
      contentType="application/octet-stream"
    contentsEncoded=cStringIO.StringIO()
    f=open(fileName,"rb")
    mainType=contentType[:contentType.find("/")]
    if mainType=="text":
      cte="quoted-printable"
      quopri.encode(f,contentsEncoded,1) # 1 for encode tabs
    else:
      cte="base64"
      base64.encode(f,contentsEncoded)
    f.close()
    subMsg=email.Message.Message()
    subMsg.add_header("Content-type",contentType,name=fileName)
    subMsg.add_header("Content-transfer-encoding",cte)
    subMsg.set_payload(contentsEncoded.getvalue())
    contentsEncoded.close()
    mainMsg.attach(subMsg)

  f=open(outputFile,"wb")
  f.write(mainMsg.as_string())
  f.close()
  return None

if __name__=="__main__":
  main()

Discussion

The email module makes manipulating MIME messages easier than it was before. It's still not trivial so the example may be useful. (Updated to use email modle's more recent API.)

Comments

  1. 1. At 3:39 a.m. on 21 jan 2004, Hans Fangohr said:

    Good work! Excellent example -- this was exactly what I needed.

    I think the email module has changed slightly since this example was written: I suppose the 'subMsg.add_payload' command should be replaced by 'subMsg.set_payload' and the 'mainMsg.add_payload' command should be replaced by 'mainMsg.attach'. However, I'd leave it to some more knowledgable person to confirm this.

    Other than that, the example runs fine and helped me a lot. Thanks, Hans

  2. 2. At 6:22 p.m. on 29 apr 2004, John Pywtorak said:

    Python 2.2.1 and older ok, but 2.2.2+ need a little more. For the Generator use the flatten method as the __call__ method is depricated.

    The Message method add_payload is depricated in favor of attach, however with a multipart/mixed you should be using set_payload in all the attached messages. Use attach in your main message, the one that has the content-type multipart/mixed. The sub messages with other content-types like text/plain, application/pdf, etc you use set_payload.

    If you do not do this you will get an exception, or error that says something like: TypeError string payload expected: type list from the Generator.py module

    This is because by using attach, or add_payload the payload becomes a list and the content-type won't match, so the generator bombs.

    Johnny P

  3. 3. At 4:30 p.m. on 1 may 2005, Gregory Eckersley said:

    I had problems using the "attach" method and found reference to this problem in your comments re this example. This looks like a bug in the current (>= 2.3) python versions (it has allsorts of nasty consequences other than just this example) . Have you submitted a bug report to the library maintainer . I am using 2.3 and have not yet checked 2.4. Your post was very useful - I had read and reread the python manual and was getting nowhere! Thanks.

Sign in to comment