An example of using the email module to create a multipart MIME message.
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.)
Tags: network
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
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
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.