Python email get message

How to fetch an email body using imaplib in python?

I’d like to fetch the whole message from IMAP4 server. In python docs if found this bit of code that works:

>>> t, data = M.fetch('1', '(RFC822)') >>> body = data[0][1] 

I’m wondering if I can always trust that data[0][1] returns the body of the message. When I’ve run ‘RFC822.SIZE’ I’ve got just a string instead of a tuple. I’ve skimmed through rfc1730 but I wasn’t able to figure out the proper response structure for the ‘RFC822’. It is also hard to tell the fetch result structure from imaplib documentation. Here is what I’m getting when fetching RFC822 :

('OK', [('1 (RFC822 ', 'body of the message', ')')]) 

How should I properly handle the data[0] list? Can I trust that when it is a list of tuples the tuples has exactly 3 parts and the second part is the payload? Maybe you know any better library for imap4?

4 Answers 4

No. imaplib is a pretty good library, it’s imap that’s so unintelligible.

You may wish to check that t == ‘OK’ , but data[0][1] works as expected for as much as I’ve used it.

Here’s a quick example I use to extract signed certificates I’ve received by email, not bomb-proof, but suits my purposes:

import getpass, os, imaplib, email from OpenSSL.crypto import load_certificate, FILETYPE_PEM def getMsgs(servername="myimapserverfqdn"): usernm = getpass.getuser() passwd = getpass.getpass() subject = 'Your SSL Certificate' conn = imaplib.IMAP4_SSL(servername) conn.login(usernm,passwd) conn.select('Inbox') typ, data = conn.search(None,'(UNSEEN SUBJECT "%s")' % subject) for num in data[0].split(): typ, data = conn.fetch(num,'(RFC822)') msg = email.message_from_string(data[0][1]) typ, data = conn.store(num,'-FLAGS','\\Seen') yield msg def getAttachment(msg,check): for part in msg.walk(): if part.get_content_type() == 'application/octet-stream': if check(part.get_filename()): return part.get_payload(decode=1) if __name__ == '__main__': for msg in getMsgs(): payload = getAttachment(msg,lambda x: x.endswith('.pem')) if not payload: continue try: cert = load_certificate(FILETYPE_PEM,payload) except: cert = None if cert: cn = cert.get_subject().commonName filename = "%s.pem" % cn if not os.path.exists(filename): open(filename,'w').write(payload) print "Writing to %s" % filename else: print "%s already exists" % filename 

Presumably higher-level imap libraries need to deal with foibles between different imap implementations, or be incompatible.

I am currently experiencing that data[0] is actually just a bytes object and not a tuple of (bytes, bytes) . My application continuously polls for new (unseen) messages from the IMAP server and this behaviour occurs when I mark the message as unread from the web interface. The service is at web.de. More specifically, usually the data format is [(bytes, bytes), bytes] but when the message is marked as unseen manually, the format is [bytes, (bytes, bytes), bytes]

Читайте также:  Символы запрещенные в html

The IMAPClient package is a fair bit easier to work with. From the description:

Easy-to-use, Pythonic and complete IMAP client library.

I support that. IMAPClient is very to use and object oriented. It is much easier to use than imaplib and has no major issues.

from imap_tools import MailBox # get list of email bodies from INBOX folder with MailBox('imap.mail.com').login('test@mail.com', 'password', 'INBOX') as mailbox: bodies = [msg.text or msg.html for msg in mailbox.fetch()] 
  • Basic message operations: fetch, uids, numbers
  • Parsed email message attributes
  • Query builder for search criteria
  • Actions with emails: copy, delete, flag, move, append
  • Actions with folders: list, set, get, create, exists, rename, subscribe, delete, status
  • IDLE commands: start, poll, stop, wait
  • Exceptions on failed IMAP operations
  • No external dependencies, tested

This was my solution to extract the useful bits of information. It’s been reliable so far:

import datetime import email import imaplib import mailbox EMAIL_ACCOUNT = "your@gmail.com" PASSWORD = "your password" mail = imaplib.IMAP4_SSL('imap.gmail.com') mail.login(EMAIL_ACCOUNT, PASSWORD) mail.list() mail.select('inbox') result, data = mail.uid('search', None, "UNSEEN") # (ALL/UNSEEN) i = len(data[0].split()) for x in range(i): latest_email_uid = data[0].split()[x] result, email_data = mail.uid('fetch', latest_email_uid, '(RFC822)') # result, email_data = conn.store(num,'-FLAGS','\\Seen') # this might work to set flag to seen, if it doesn't already raw_email = email_data[0][1] raw_email_string = raw_email.decode('utf-8') email_message = email.message_from_string(raw_email_string) # Header Details date_tuple = email.utils.parsedate_tz(email_message['Date']) if date_tuple: local_date = datetime.datetime.fromtimestamp(email.utils.mktime_tz(date_tuple)) local_message_date = "%s" %(str(local_date.strftime("%a, %d %b %Y %H:%M:%S"))) email_from = str(email.header.make_header(email.header.decode_header(email_message['From']))) email_to = str(email.header.make_header(email.header.decode_header(email_message['To']))) subject = str(email.header.make_header(email.header.decode_header(email_message['Subject']))) # Body details for part in email_message.walk(): if part.get_content_type() == "text/plain": body = part.get_payload(decode=True) file_name = "email_" + str(x) + ".txt" output_file = open(file_name, 'w') output_file.write("From: %s\nTo: %s\nDate: %s\nSubject: %s\n\nBody: \n\n%s" %(email_from, email_to,local_message_date, subject, body.decode('utf-8'))) output_file.close() else: continue 

Источник

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

30 марта 2017 г. Archy Просмотров: 55811 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)
Читайте также:  Html all tags and codes

Далее мы извлечем необходимые нам данные из ответа, затем получим почту, через вычисленный нами 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.

Читайте также:  Создание HTML-таблиц

А ссылку на оригинал? (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() Это не работает. Дальнейшее не имеет смысла.

Источник

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