Python imaplib search since

Harbinger’s Hollow

The imaplib IMAP4 “search” method is very powerful because it allows mail to be filtered on the mail server before ever sending the results back across the network. The following example returns a list of messages numbers for all unread messages newer than the 1st of the year that do not contain “Smith” in the “From” header:

mbox.search(None, 'UNSEEN SINCE 1-Jan-2010 NOT FROM "Smith"')

Like many other IMAP4 object methods, you won’t find the options for this search parameter in the Python imaplib documentation. This is because those parameters are specified in detail inside RFC3501; The Internet Message Access Protocol – Version 4rev1 standard.

RFC’s are great; they’re very detailed, but they were never designed to be user-friendly how-to’s. For example the search string parameter options accepted by IMAP4’s SEARCH command are strewn across five (5) different pages in the RFC and are listed in alphabetical order rather than grouped by function.

For future reference I decided to create an IMAPv4 SEARCH command reference, i.e. cheat-sheet. I’ve grouped the commands by:

  • Search for String in Message commands
  • Search for Message with Flags Set commands
  • Search for Messages with Flags Not Set commands
  • Search on Internal Message Date commands
  • Search on Message Header Date commands
  • Search on Message Size commands
Читайте также:  Sorting object list python

Note: If you use Lotus Notes the mailbox must be full-text indexed before the IMAP4 SEARCH command will work.

Источник

Yet another enthusiast blog!

There is no great achievement without great challenges.

Fetching all messages since last check with Python + Imap

Recently, in a freelance project I had to parse incoming mails wherever they are in the mail account and, preferably, avoid re-parsing the whole mail account only for a couple of new mails.

Fortunately, there is the low level imaplib module in Python’s toolbox. But, curiously enough, while the solution is quite simple, I have not been able to find any good solution on the net…

By default, when you perform a SEARCH on an IMAP folder, it will provide you will relative identifiers in the folder meaning that any operation on the folder might alter them. Another option, not obvious for an IMAP newcommer is to use UIDs instead. These constants IDs uniquely identifies a given during its lifetime in the mail account and are allocated in a strictly growing manner. This basically means that you can rely on this information to affirm that a given mail arrived in the mailbox after another one.

Last interesting property, the IMAP SEARCH command return all mails whose UID is in a given range, wildcard included.

For this projects, I also wrote it as a generator so that it yields at each new mail, if any. Here is a stripped down code snippet highlighting the main steps from connection negotiation to yielding individual mail bodies:

# -*- coding: utf-8 -*- import imaplib # new mail generator --> yield after each mail to save resources def new_mail(last_uid, host, port, login, password): # connect mail_server = imaplib.IMAP4(host, port) # authenticate mail_server.login(login, password) # issue the search command of the form "SEARCH UID 42:*" command = "UID <>:*".format(last_uid) result, data = mail_server.uid('search', None, command) messages = data[0].split() # yield mails for message_uid in messages: # SEARCH command *always* returns at least the most # recent message, even if it has already been synced if int(message_uid) > last_uid: result, data = mail_server.uid('fetch', message_uid, '(RFC822)') # yield raw mail body yield data[0][1] # usage example for mail in new_mail_generator(last_uid=42, host="imap.example.com", port=143, login="user@exampl.com", password="password"): # do something useful with raw mail pass
  • Loop over all folders. (hint: see “list” method to get a folder list)
  • Save sync status to a persistent storage like a database
  • Parse mail body
  • Handle secure connections

If you need any help in your Python/Imap related project, feel free to get in touch

Jean-Tiare Le Bigot

Источник

Читаем почту через IMAP в Python

30 марта 2017 г. Archy Просмотров: 55848 RSS 9
Примеры Python imap python, imaplib, почта imap, протокол imap

IMAP Python

У меня не вышло найти всю необходимую информацию об IMAP в интернете, кроме RFC3501. Документ протокола IMAP Python – ключ к пониманию доступных пользователю команд, однако позвольте пропустить попытки объяснить все сразу, и лучше взглянем на пример, где я смогу объяснить основные принципы работы

Заходим в почтовый ящик

import imaplib mail = imaplib.IMAP4_SSL('imap.gmail.com') mail.login('myusername@gmail.com', 'mypassword') mail.list() # Выводит список папок в почтовом ящике. mail.select("inbox") # Подключаемся к папке "входящие".
  • Выбираем последние письма
  • Начнем с поиска входящих среди всех писем при помощи функции поиска
  • Воспользуемся встроенным ключом “ALL”, чтобы получить все результаты (документировано в RFC3501)

Далее мы извлечем необходимые нам данные из ответа, затем получим почту, через вычисленный нами ID.

result, data = mail.search(None, "ALL") ids = data[0] # Получаем сроку номеров писем id_list = ids.split() # Разделяем ID писем latest_email_id = id_list[-1] # Берем последний ID result, data = mail.fetch(latest_email_id, "(RFC822)") # Получаем тело письма (RFC822) для данного ID raw_email = data[0][1] # Тело письма в необработанном виде # включает в себя заголовки и альтернативные полезные нагрузки

Используем UID вместо ID

Функция поиска imap возвращает последовательный ID: если значение ID равно 5, значит это пятый электронный адрес в вашей почте. Это значит, что когда пользователь удаляет адрес под номером 10, все письма, находящиеся выше этой отметки указывают на неправильный адрес.

Это неприемлемо!

Не можете найти дешевых подписчиков в YouTube с гарантиями? Предлагаем Вам обратиться за помощью по ссылке и сделать выгодную покупку на надежном сайте SMM услуг. Здесь Вы получите качественный гарантированный ресурс по заманчивым ценам.

К счастью, мы можем отправить запрос на сервер imap и вернуть уникальный id (UID). Это работает очень просто: мы используем функцию uid и передаём её строке команды in в качестве первого аргумента. Остальная часть кода остается неизменной.

result, data = mail.uid('search', None, "ALL") # Выполняет поиск и возвращает UID писем. latest_email_uid = data[0].split()[-1] result, data = mail.uid('fetch', latest_email_uid, '(RFC822)') raw_email = data[0][1]

Анализ необработанных писем

Работа с почтой очень похожа на разбор невнятной речи. К счастью, мы располагаем библиотекой python для работы с почтой, которая называется, кто бы мог подумать, email. Данная библиотека может конвертировать необработанные письма в знакомый нам объект EmailMessage.

import email email_message = email.message_from_string(raw_email) print email_message['To'] print email.utils.parseaddr(email_message['From']) # получаем имя отправителя "Yuji Tomita" print email_message.items() # Выводит все заголовки. def get_first_text_block(self, email_message_instance): maintype = email_message_instance.get_content_maintype() if maintype == 'multipart': for part in email_message_instance.get_payload(): if part.get_content_maintype() == 'text': return part.get_payload() elif maintype == 'text': return email_message_instance.get_payload()

Расширенный поиск

Мы только что закончили с базовым поиском для всей почты в целом. Теперь мы научимся сортировать выдачу поиска на нужную и ненужную. Все доступные параметры поиска находятся в протокольной документации IMAP, так что вам определенно захочется ознакомиться с разделом SEARCH Command поближе.

Попробуем следующие способы поиска.

Поиск любых заголовков

Для поиска заголовков, так их как «Ответы», «Входящие» и т.д., используем команду (HEADER “”)

mail.uid('search', None, '(HEADER Subject "My Search Term")') mail.uid('search', None, '(HEADER Received "localhost")')

Поиск писем, начиная с датированных вчерашним днем

Часто количество входящих сообщений слишком велико, и в IMAP не указывается способ ограничения результатов, и это делает поиск слишком медленным. Существует способ ограничить этот объем – использовать ключевое слово SENTSINCE. Формат даты SENTSINCE будет следующими: ДД-МММ-ГГГГ. В то время как Python формат будет следующем: strftime(‘%d-%b-%Y’)

import datetime date = (datetime.date.today() - datetime.timedelta(1)).strftime("%d-%b-%Y") result, data = mail.uid('search', None, '(SENTSINCE )'.format(date=date))

Ограничение по дате, поиск по темам и исключение отправителей

date = (datetime.date.today() - datetime.timedelta(1)).strftime("%d-%b-%Y") result, data = mail.uid('search', None, '(SENTSINCE HEADER Subject "My Subject" NOT FROM "yuji@grovemade.com")'.format(date=date))

Выборка

Получаем ID переписки Gmail

Выборка может включать в себя как все тело письма, так и любое сочетание результатов выдачи, такие как отмеченные письма (просмотренные\не просмотренные). Также это касается и определенных ID в Gmail, таких как ID переписки.

result, data = mail.uid('fetch', uid, '(X-GM-THRID X-GM-MSGID)')

Получаем только ключ заголовка

result, data = mail.uid('fetch', uid, '(BODY[HEADER.FIELDS (DATE SUBJECT)]])')

Множественная выборка

Вы можете выбрать несколько писем за раз. Опытным путем я пришел к тому, что это обязательно подразумевает ввод данных через запятую.

result, data = mail.uid('fetch', '1938,2398,2487', '(X-GM-THRID X-GM-MSGID)')

Используем регулярное выражение для анализа

Полученную выдачу достаточно трудно понять, так как результат разделен парами «ключ-значение». Так что мы используем регулярное выражение для получения необходимых данных. Это достаточно просто:

result, data = mail.uid('fetch', uid, '(X-GM-THRID X-GM-MSGID)') re.search('X-GM-THRID (?P\d+) X-GM-MSGID (?P\d+)', data[0]).groupdict() # это ваш спасательный круг, который поможет организовать большой объем полученных данных.

Подведем итоги

Поздравляем, теперь вы свободно ориентируетесь в протоколе IMAP и можете использовать Python для работы с Gmail.

А ссылку на оригинал? (https://yuji.wordpress.com/2011/06/22/python-imaplib-imap-example-with-gmail/)

«Функция поиска imap возвращает последовательный ID: если значение ID равно 5, значит это пятый электронный адрес в вашей почте.» – бред какой-то! Это пятое по счету письмо в папке входящих, а вовсе не пятый адрес электронной почты. Адрес электронной почты, он же e-mail – это, например, fuckinshit@yandex.ru. И писем от с этого адреса может быть десять или тысяча. Похоже, автор не понимает, о чем пишет.

Под заголовком «Анализ необработанных писем» приведет кусок кода, явно относящийся к версии языка Python 2. А всё, что до этого, было для Python 3. Автор издевается?

В куске кода под заголовком «Анализ необработанных писем» грубая ошибка во второй строке. Функция email.message_from_stringтребует строку в качестве аргумента, а raw_email – это байтовый список. Вместо message_from_string нужно использовать message_from_bytes

Если оставить этот код без изменений, то вылетает длинное сообщение об ошибке, заканчивающееся строкой TypeError: initial_value must be str or None, not bytes Это потому, что raw_email – вовсе не строка текста, а список байтов. У меня в последнем письме этот список выглядит так: b’Received: from iva6-94240f0bdfbb.qloud-c.yandex.net. ‘ Видите символ b перед строкой? Признак байтов. Элемент raw_email[0] не равен ‘R’, он равен 82.

import imaplib mail = imaplib.IMAP4_SSL(‘imap.gmail.com’) mail.login(‘my_adress’, ‘mypassword’) mail.list() Это не работает. Дальнейшее не имеет смысла.

Источник

Оцените статью