Welcome, guest | Sign In | My Account | Store | Cart

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

Python, 62 lines
 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()

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.)

3 comments

Hans Fangohr 20 years, 3 months ago  # | flag

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

John Pywtorak 19 years, 11 months ago  # | flag

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

Gregory Eckersley 18 years, 11 months ago  # | flag

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.