Closed allan-simon closed 3 years ago
Yes it's totally legit, I'll add a section in the README to show different use cases with IMAP. Thank you for your message.
During the while, you can see https://imapwiki.org/ClientImplementation that has examples of IMAP commands and how to use them properly.
thanks for your reply
I've played a bit more with your library and right now I got the following working and doing what i want, I'm interested in feedback and maybe it can be a short real life usage (i.e basically I check INBOX, i call a treat_email function and based on treatment result, I move to a folder or another, and i reput the mail as 'unread' in case of error , so that it catches my attention)
@asyncio.coroutine
def idle_loop(host, user, password):
imap_client = aioimaplib.IMAP4_SSL(host=host, timeout=30)
yield from imap_client.wait_hello_from_server()
yield from imap_client.login(user, password)
response = yield from imap_client.select('INBOX')
while True:
response = yield from imap_client.uid('fetch', '1:*', 'RFC822')
# start is: 2 FETCH (UID 18 RFC822 {42}
# middle is the actual email content
# end is simply ")"
# the last line is removed as it's only "success"-ish information
# the iter + zip tricks is to iterate three by three
iterator = iter(response.lines[:-1])
for start, middle, _end in zip(iterator, iterator, iterator):
# stat and end are string but middle is bytes
if not isinstance(middle, bytes):
continue
# index 3 because the actual id is at the position 3
# 0 1 2 3
# | | | |
# v v v v
# 2 FETCH (UID 18 RFC822 {42}
email_uid = start.split(' ')[3]
# mailparser come from this library:
# https://github.com/SpamScope/mail-parser
# saved me a lot of hassle (especially dealing with attachements and text / html version of the email)
parsed_email = mailparser.parse_from_bytes(middle)
treated_correctly = treat_email(parsed_email)
if treated_correctly:
yield from imap_client.uid(
'move',
email_uid + ':' + email_uid ,
'treated'
)
else:
yield from imap_client.uid(
'store',
email_uid,
'-FLAGS',
'(\Seen)'
)
yield from imap_client.uid(
'move',
email_uid + ':' + email_uid ,
'automation-error'
)
idle = yield from imap_client.idle_start(timeout=60)
print((yield from imap_client.wait_server_push()))
imap_client.idle_done()
yield from asyncio.wait_for(idle, 30)
Thanks for your loop that seems right to me. In our application we are checking the messages headers first since the bigger UID (persisted locally) :
MessageAttributes = namedtuple('MessageAttributes', 'uid flags sequence_number')
ID_HEADER_SET = {'Content-Type', 'From', 'To', 'Cc', 'Bcc', 'Date', 'Subject',
'Message-ID', 'In-Reply-To', 'References'}
FETCH_MESSAGE_DATA_SEQNUM = re.compile(r'(?P<seqnum>\d+) FETCH.*')
FETCH_MESSAGE_DATA_FLAGS = re.compile(r'.*FLAGS \((?P<flags>.*?)\).*')
FETCH_MESSAGE_DATA_UID = re.compile(r'.*UID (?P<uid>\d+).*')
response = await self.aioimap.uid('fetch', '%d:*' % (max_uid + 1),
'(UID FLAGS BODY.PEEK[HEADER.FIELDS (%s)])' % ' '.join(ID_HEADER_SET))
if response.result == 'OK':
for i in range(0, len(response.lines) - 1, 3):
fetch_command_without_literal = '%s %s' % (response.lines[i], response.lines[i+2])
seqnum = FETCH_MESSAGE_DATA_SEQNUM.match(fetch_command_without_literal).group('seqnum')
flags = FETCH_MESSAGE_DATA_FLAGS.match(fetch_command_without_literal).group('flags')
uid = FETCH_MESSAGE_DATA_UID.match(fetch_command_without_literal).group('uid')
message = BytesHeaderParser().parsebytes(response.lines[i+1]) # from stdlib email parser
message_attrs = MessageAttributes(uid, flags, seqnum)
# then display or store message/message_attrs
else:
logger.warn(...)
Then later get the body of the mail :
dwnld_resp = await self.aioimap.uid('fetch', uid, 'BODY.PEEK[]')
body = dwnld_resp.lines[1]
# then treat body
I've added a file for example because it was too lengthy for the README
I close this issue you can reopen it if it doesn't fit your needs
I'm looking at this, and it is way over my head. I noticed that you aren't doing anything with fetch_message_body. Is there anyway you could extend the example (or maybe condense? ha. I don't understand a lot of what is going on. I guess because it is probably low level?).
This example for imaplib: https://gist.githubusercontent.com/robulouski/7441883/raw/550e72da01e84539ccf501df0daf3c91742061b2/gmail_imap_example.py
I was able to figure out how to print messages and iterate over messages. Could you do the same for this?
I think I figured out how to print the emails:
async def idle_loop(host, user, password):
imap_client = aioimaplib.IMAP4_SSL(host=host, timeout=30)
await imap_client.wait_hello_from_server()
await imap_client.login(user, password)
await imap_client.select()
items = []
while True:
a = await imap_client.uid('fetch', '1:*', 'FLAGS')
print(len(a[1]))
for itm in a[1]:
x = FETCH_MESSAGE_DATA_UID.search(itm)
if x is not None:
message = await fetch_message_body(imap_client, x.groupdict()['uid'])
print(message)
emails = FIND_EMAIL.findall(message.as_string())
print(emails)
await imap_client.uid('store', x.groupdict()['uid'], '\\Deleted')
##email_search= FIND_EMAIL.findall(message)
# print(email_search)
idle = await imap_client.idle_start(timeout=60)
print((await imap_client.wait_server_push()))
imap_client.idle_done()
await asyncio.wait_for(idle, 30)
How would I go about deleting?
I think you can do :
await self.aioimap.uid('store', msg_uid, '+FLAGS.SILENT', '(\Deleted)')
await self.aioimap.uid('expunge', msg_uid)
Hi guys!
Sorry if I look noob but I'm quite a beginner with the use of IMAP and even more with the use of threads in Python.
I was trying to use this code but I cannot find a way to keep listening until an email with a certain subject arrives and print that email's body.
Do you have some complete examples of how to do it?
I'd really really appreciate it.
Hello
first thanks for this library, as it seems to be the only one for imap and asyncio :) I'm pretty noob to the IMAP protocol and what i find missing is a bit of examples in the README.md on how to do some basic tasks (like actually receiving an email)
for example the IDLE example does show me that I've "received something" but I've no clue how to treat it :) having some more examples in the readme would compensate not having a formal documentation
thanks again