0

There's an email blasted out every morning containing an Excel attachment. I would like to be able to grab each of these attachments and save them into the same folder. I attempted the following code:

Downloading multiple attachments using imaplib

https://gist.github.com/jasonrdsouza/1674794

https://gist.github.com/baali/2633554

But I keep running into the same error:

initial_value must be str or None, not bytes

I assume this is because there's something wrong with one of the emails/attachments, but I'm not sure how to troubleshoot.

Code:

detach_dir = 'C:/Users/myname'
m = imaplib.IMAP4_SSL("outlook.office365.com")
m.login('emailaddress@server.com','password')
m.select("INBOX")

resp, items = m.search(None, '(SUBJECT "Daily Report")')
items = items[0].split()

for emailid in items:
    resp, data = m.fetch(emailid, "(RFC822)") 
    email_body = data[0][1] 
    mail = email.message_from_string(email_body)
    #^This is where the error occurs
    temp = m.store(emailid,'+FLAGS', '\\Seen')
    m.expunge()

    if mail.get_content_maintype() != 'multipart':
        continue

    #print "["+mail["From"]+"] :" + mail["Subject"]

   for part in mail.walk():
       if part.get_content_maintype() == 'multipart':
           continue
       if part.get('Content-Disposition') is None:
           continue

       filename = part.get_filename()
       att_path = os.path.join(detach_dir, filename)

       if not os.path.isfile(att_path) :
           fp = open(att_path, 'wb')
           fp.write(part.get_payload(decode=True))
           fp.close()

This is the error:

TypeError                                 Traceback (most recent call last)
<ipython-input-6-07c04531d5aa> in <module>()
      5     resp, data = m.fetch(emailid, "(RFC822)")
      6     email_body = data[0][1]
----> 7     mail = email.message_from_string(email_body)
      8     #This is where the error occurs
      9     temp = m.store(emailid,'+FLAGS', '\\Seen')

~\AppData\Local\Continuum\anaconda3\lib\email\__init__.py in message_from_string(s, *args, **kws)
     36     """
     37     from email.parser import Parser
---> 38     return Parser(*args, **kws).parsestr(s)
     39 
     40 def message_from_bytes(s, *args, **kws):

~\AppData\Local\Continuum\anaconda3\lib\email\parser.py in parsestr(self, text, headersonly)
     66         the file.
     67         """
---> 68         return self.parse(StringIO(text), headersonly=headersonly)
     69 
     70 

TypeError: initial_value must be str or None, not bytes

The code works fine when I tested it for a different subject, so I assume there's one email or attachment that's screwing it up. Reducing the search to emails sent on Jan 1 onwards might do the trick, but I don't know how to manipulate the search for two parameters:

typ, msgs = mails.search(None, '(SUBJECT "Daily Report")', 'SENTSINCE 01-JAN-2018')
Marshall Gu
  • 137
  • 3
  • 14
  • 1
    Edited the question. – Marshall Gu Jan 25 '18 at 15:24
  • I don't have any experience with your problem, but an obvious omission in your description is the answer to the questions "Does this happen with every email? Does this happen with every email with attachment?" – Mr. T Jan 25 '18 at 15:27
  • Yeah, I sent myself two emails with attachments under a different subject and the script went fine. I assume there's something wrong with one of the emails/attachments... I just tried limiting the search to attachments sent since January 1 typ, msgs = mails.search(None, '(SUBJECT "Daily Report")', 'SENTSINCE 01-JAN-2018') But I don't think that's the way to do it...? – Marshall Gu Jan 25 '18 at 16:03
  • Edited into the question. – Marshall Gu Jan 25 '18 at 16:07
  • Python2 or Python3? – Max Jan 26 '18 at 14:39

1 Answers1

1

Change the line to: mail = email.message_from_bytes(email_body)

Petr Vala
  • 11
  • 3