5

I inadvertently marked all the messages in my inbox as read with this python statement:

status, data = conn.uid('fetch', fetch_uids, '(RFC822)')

But I was able to walk through all the parts of the message with the following set of statments:

email_message = email.message_from_string(data[0][1])
for part in email_message.walk():
  print '\n'
  print 'Content-Type:',part.get_content_type()
  print 'Main Content:',part.get_content_maintype()
  print 'Sub Content:',part.get_content_subtype()

The output:

Content-Type: multipart/mixed
Main Content: multipart
Sub Content: mixed


Content-Type: multipart/alternative
Main Content: multipart
Sub Content: alternative


Content-Type: text/plain
Main Content: text
Sub Content: plain


Content-Type: text/html
Main Content: text
Sub Content: html

I found that if I used this statement instead:

status, data = conn.uid('fetch', fetch_uids, '(RFC822.HEADER BODY.PEEK[1])')

that I wouldn't mark all of my messages read. However, I also wouldn't get all the parts of the message:

Content-Type: multipart/mixed
Main Content: multipart
Sub Content: mixed

I tried to read the manual for imaplib here, but the word "peek" is not mentioned. My question is, how do I get all the parts of the message while not marking my messages as read? Thanks.

nomadicME
  • 1,389
  • 5
  • 15
  • 35

4 Answers4

3

You can also open the mailbox in readonly mode. select(folder, readonly=True)

Seraj Ahmad
  • 405
  • 6
  • 10
2

I guess if you just keep trying enough combinations, you'll find your answer:

status, data = conn.uid('fetch', fetch_ids, '(RFC822 BODY.PEEK[])')

Along the way I found a lot of information in the RFC 1730 manual.

Community
  • 1
  • 1
nomadicME
  • 1,389
  • 5
  • 15
  • 35
  • 2
    I take it back, this still marks messages as read, which is surprising since I'm still using `body.peek[]`. – nomadicME Jun 12 '12 at 18:29
  • 1730 is long obsolete. The [RFC3501](https://tools.ietf.org/html/rfc3501) equivalent is simply `BODY.PEEK[]`. – tripleee Mar 05 '19 at 08:48
2

I think I am talking to myself, just in a formal way. :)

I think I really found the answer this time:

status, data = conn.uid('fetch', fetch_ids, '(BODY.PEEK[])')

This does everything that I was looking for. It does not mark the message as read (Seen), and it retrieves all parts of the message.

Looking at the RFC 1730 manual it seemed like this should have worked:

status, data = conn.uid('fetch', fetch_ids, '(RFC822.PEEK BODY)')

but that produced an error as well???

nomadicME
  • 1,389
  • 5
  • 15
  • 35
  • As a result of doing it this way, the header is not separate from the body, which I kind of like anyway. The entire header is displayed with the body. – nomadicME Jun 13 '12 at 04:10
1

If you want just the headers, but still want the message to be left marked unread (UNSEEN), it requires two commands fetch and then store:

# get uids of unseen messages
result, uids = conn.uid('search', None, '(UNSEEN)')

# convert these uids to a comma separated list
fetch_ids = ','.join(uids[0].split())

# first fetch the headers, this will mark them read (SEEN)
status, headers = conn.uid('fetch', fetch_ids, '(RFC822.HEADER)')

# now mark each message unread (UNSEEN)
status1, flags = conn.uid('store', fetch_ids,'-FLAGS','\\Seen')
nomadicME
  • 1,389
  • 5
  • 15
  • 35
  • While this probably works in a limited setting, the usual approach is to use readonly or peek. Anything non-atomic has obvious issues in a protocol where concurrent access is a required feature. This should not be the accepted answer. – tripleee Feb 12 '16 at 10:20