0

I'm trying to find mails matching a particular FROM address. I've looked at this answer but it doesn't work for me.

Here's the relevant code:

import imaplib

conn = imaplib.IMAP4_SSL(IMAPserver)
conn.login(IMAPuserName, IMAPpassword)
retVal, data = conn.select("INBOX")
    if retVal != "OK":
        <PRINT SOME ERROR MESSAGE>
        sys.exit(1)

All this works. Here are some variations of the search command that don't work:

retVal, data = conn.search(None, 'UNSEEN HEADER FROM "foo@example.com"')

retVal, data = conn.search(None, 'UNSEEN FROM "foo@example.com"')

retVal, data = conn.search(None, 'FROM "foo@example.com"')

retVal, data = conn.search(None, 'HEADER FROM "foo@example.com"')

All of these result in errors like these:

    imaplib.error: SEARCH command error: BAD ['Error in IMAP command SEARCH: 
Unexpected string as search key: FROM "foo@example.com"']

I've referred to the relevant section of the IMAP v4 RFC but I can't figure out what exactly I'm doing wrong. Any help would be greatly appreciated.

Community
  • 1
  • 1
hyperwiser
  • 437
  • 1
  • 5
  • 19
  • I think your server may have badly/unimplemented search. Some off-brand servers just don't support string searching. (eg, mail.ru appears to be one of them). What service and/or server software are you trying to connect to? Those commands look ok to me. – Max Nov 21 '16 at 17:16
  • Thanks, @Max. That possibility did occur to me but it is a bit difficult to verify. This is a private company email server which I don't have much control over or insight into. – hyperwiser Nov 22 '16 at 11:45

2 Answers2

2

As shown in the examples in the docmentation, IMAP.search() expects the search arguments as individual, positional arguments, not as a single string:

conn.search(None, 'UNSEEN', 'HEADER', 'FROM', 'foo@example.com')
conn.search(None, 'UNSEEN', 'FROM', 'foo@example.com')
conn.search(None, 'FROM', 'foo@example.com')
conn.search(None, 'HEADER', 'FROM', 'foo@example.com')

If you pass in a single argument, imaplib will pass it as a single quoted argument to the SEARCH command.

Again, however, you cannot rely on this, since the quoting only happens for Python 2.x imaplib. Python 3.x imaplib does not do the quoting for you and that particular bug is still open.

One way around that --as stated by the documentation-- is to "pre-quote" the arguments as a list:

conn.search(None, '(UNSEEN HEADER FROM foo@example.com)')
conn.search(None, '(UNSEEN FROM foo@example.com)')
conn.search(None, '(FROM foo@example.com)')
conn.search(None, '(HEADER FROM foo@example.com)')

But as noted by @Max, this is not supported by some IMAP servers.

dhke
  • 15,008
  • 2
  • 39
  • 56
  • Your first set of commands are equivalent to his. The imaplib just concatenates the various substrings with spaces. The second set may confuse some servers which do not expect ()s at the top level. – Max Nov 21 '16 at 17:17
  • @Max I can quite definitely confirm that at least Cyrus IMAP croaks on `imap.search(None, 'FROM "localpart@domain"')`, while it gladly accepts `imap.search(None, 'FROM', 'localpart@domain')`. If you don't pass individual arguments, you will get the whole string passed as one quoted argument to the IMAP server (via `IMAP._quote()`). – dhke Nov 21 '16 at 17:41
  • Ah, I used 3.0 imaplib (and forks) – Max Nov 21 '16 at 21:08
  • Interestingly, this is what I was doing before what i wrote in my OP: conn.search(None, 'FROM', 'foo@example.com') That did not barf, but it matched each and every message in the mailbox regardless of the actual FROM header. Is this a server-side SEARCH implementation problem as @Max suggested above? – hyperwiser Nov 22 '16 at 12:40
  • Does a list of server capabilities help diagnose the problem? * CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS SPECIAL-USE QUOTA – hyperwiser Nov 22 '16 at 12:47
2

I managed to get info from the guys managing the IMAP server. This was a server problem and not something to do with the code.

The IMAP server in question is a customised version of Dovecot. It actually indexes all mailboxes to make searching etc. faster. In this particular case the index for my mailbox had gotten corrupted. Re-indexing fixed the problem.

hyperwiser
  • 437
  • 1
  • 5
  • 19