[plug] MIME Types by file contents

Craig Ringer craig at postnewspapers.com.au
Tue Jul 6 13:53:15 WST 2004


Bernd Felsche wrote:

> I get a bunch of errors like:
> bernie at pinion:~> python bin/maildoc.py bernie < z25 
> Traceback (most recent call last):
>   File "bin/maildoc.py", line 143, in ?
>     if __name__ == '__main__': main()
>   File "bin/maildoc.py", line 140, in main
>     os.popen("/usr/sbin/sendmail -t","w").write(message.as_string())
>   File "/var/tmp/python-2.2.2-build//usr/lib/python2.2/email/Message.py", line 107, in as_string
>   File "/var/tmp/python-2.2.2-build//usr/lib/python2.2/email/Generator.py", line 100, in flatten
>   File "/var/tmp/python-2.2.2-build//usr/lib/python2.2/email/Generator.py", line 128, in _write
>   File "/var/tmp/python-2.2.2-build//usr/lib/python2.2/email/Generator.py", line 154, in _dispatch
>   File "/var/tmp/python-2.2.2-build//usr/lib/python2.2/email/Generator.py", line 243, in _handle_multipart
>   File "/var/tmp/python-2.2.2-build//usr/lib/python2.2/email/Generator.py", line 100, in flatten
>   File "/var/tmp/python-2.2.2-build//usr/lib/python2.2/email/Generator.py", line 128, in _write
>   File "/var/tmp/python-2.2.2-build//usr/lib/python2.2/email/Generator.py", line 154, in _dispatch
>   File "/var/tmp/python-2.2.2-build//usr/lib/python2.2/email/Generator.py", line 302, in _handle_message
>   File "/var/tmp/python-2.2.2-build//usr/lib/python2.2/email/Message.py", line 179, in get_payload
> TypeError: 0
> 
> whenever I feed it a saved news item. It'll probably hiccup on email as well.

> See the attached bugfest for details.

A heads-up on said "bugfest" - you've mixed space and tab indenting. 
This is probably unwise. If you drop this in your .vimrc (if you use 
vim), it'll display tabs and trailing spaces:

set listchars=tab:>-,trail:+

... really handy for this sort of thing.

I'm going to make a guess at what the problem you're having is, based on 
that info you found and the code in build_message(). I suspect the email 
package is being confused by the content-type of message/* because it 
expects a Message object for that content-type. If you look at 
Generator._dispatch, you'll see:

     def _dispatch(self, msg):
         # Get the Content-Type: for the message, then try to dispatch to
         # self._handle_<maintype>_<subtype>().  If there's no handler
	# for the
         # full MIME type, then dispatch to self._handle_<maintype>().
	# If
         # that's missing too, then dispatch to self._writeBody().
         main = msg.get_content_maintype()
         sub = msg.get_content_subtype()
         specific = UNDERSCORE.join((main, sub)).replace('-', '_')
         meth = getattr(self, '_handle_' + specific, None)
         if meth is None:
             generic = main.replace('-', '_')
             meth = getattr(self, '_handle_' + generic, None)
             if meth is None:
                 meth = self._writeBody
         meth(msg)

so for most things it'll call Generator._writeBody, but it has a handler 
for message/* so it'll call Generator._handle_message() . Here's that 
function:

     def _handle_message(self, msg):
         s = StringIO()
         g = self.clone(s)
         # The payload of a message/rfc822 part should be a multipart
	# sequence
         # of length 1.  The zeroth element of the list should be the
	# Message
         # object for the subpart.  Extract that object, stringify it,
	# and
         # write it out.
         g.flatten(msg.get_payload(0), unixfrom=False)
         self._fp.write(s.getvalue())

This is unlikely to work with a string object. I may be dead wrong here, 
as this is only a really cursory reading, but that's my guess.

Try something like this in your code (I've left unchanged bits
quoted so you can see):

       # the document part now.
       doc_type = grokMIMEtype(url)
       doc_ext = grokMIMEext(doc_type)
       doc_load = file(url,'r')
       doc_data = doc_load.read()
       if doc_type[0] == 'data':
           doc_part = MIMEBase(doc_type[0],'')
           doc_part.set_payload(doc_data)
       elif doc_type[0] == 'message':
           doc_part = MIMEMessage(doc_data, doc_type[1])
       else:
   	  doc_part = MIMEBase(doc_type[0],doc_type[1])
           doc_part.set_payload(doc_data)

       doc_part.add_header('Content-Disposition', 'attachment',
                            filename=doc_basename + doc_ext)

The above is untested, and written straight into the message. The point 
is that I suspect you need to generate a MIMEMessage instance for 
message/* content-types. Hell, it might work.

--
Craig Ringer




More information about the plug mailing list