0

I'm trying to work with email messages in Python 3.7 and struggling with what looks like compatibility issues. The docs mention email.message.Message having an iter_parts method that should allow me to do a non-recursive walk of message parts.

This doesn't exist on messages returned from mailbox messages and it's taken me a while to get it behaving. For example, I can generate a dummy message with:

from email.message import EmailMessage

msg = EmailMessage()
msg['Subject'] = 'msg 1'
msg.add_alternative("Plain text body", subtype='plain')
msg.add_alternative("<html><body><p>HTML body</p></body></html>", subtype='html')
msg.add_attachment(b"Nothing to see here!", maintype='data', subtype='raw')

and then dump out the parts with:

def iter_parts(msg):
  ret = msg.get_content_type()
  if msg.is_multipart():
    parts = ', '.join(iter_parts(m) for m in msg.iter_parts())
    ret = f'{ret} [{parts}]'
  return ret

iter_parts(msg)

which gives me: multipart/mixed [multipart/alternative [text/plain, text/plain], data/raw]

but if I save this to a mbox file and reload it:

import mailbox
mbox = mailbox.mbox('/tmp/test.eml')
mbox.add(msg)
iter_parts(mbox[0])

it tells me AttributeError: 'mboxMessage' object has no attribute 'iter_parts'

Initially I thought it might be related to https://stackoverflow.com/a/45804980/1358308 but setting factory=None doesn't seem to do much in Python 3.7.

Am posting my solution, but would like to know if there are better options!

Sam Mason
  • 15,216
  • 1
  • 41
  • 60

1 Answers1

1

After much poking and reading of source I found that I can instead do:

from email import policy
from email.parser import BytesParser

mbox = mailbox.mbox('/tmp/test.eml', factory=BytesParser(policy=policy.default).parse)

and then I get objects with an iter_parts method.

Sam Mason
  • 15,216
  • 1
  • 41
  • 60