Подтвердить что ты не робот

Получить имя файла вставки Gmail, не загружая его

Я пытаюсь получить все сообщения из учетной записи Gmail, которые могут содержать некоторые большие вложения (около 30 МБ). Мне просто нужны имена, а не целые файлы. Я нашел фрагмент кода, чтобы получить сообщение и имя вложения, но он загружает файл, а затем читает его имя:

import imaplib, email

#log in and select the inbox
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login('username', 'password')
mail.select('inbox')

#get uids of all messages
result, data = mail.uid('search', None, 'ALL') 
uids = data[0].split()

#read the lastest message
result, data = mail.uid('fetch', uids[-1], '(RFC822)')
m = email.message_from_string(data[0][1])

if m.get_content_maintype() == 'multipart': #multipart messages only
    for part in m.walk():
        #find the attachment part
        if part.get_content_maintype() == 'multipart': continue
        if part.get('Content-Disposition') is None: continue

        #save the attachment in the program directory
        filename = part.get_filename()
        fp = open(filename, 'wb')
        fp.write(part.get_payload(decode=True))
        fp.close()
        print '%s saved!' % filename

Я должен делать это один раз в минуту, поэтому я не могу загрузить сотни МБ данных. Я новичок в веб-скриптах, так может ли кто-нибудь мне помочь? Мне действительно не нужно использовать imaplib, любой python lib будет в порядке для меня.

С наилучшими пожеланиями

4b9b3361

Ответ 1

Вместо fetch RFC822, который является полным содержимым, вы можете указать BODYSTRUCTURE.

Результирующая структура данных из imaplib довольно запутанна, но вы должны иметь возможность находить имя файла, тип содержимого и размеры каждой части сообщения, не загружая все.

Ответ 2

Если вы знаете что-то о имени файла, вы можете использовать расширения X-GM-RAW gmail для команды imap SEARCH. Эти расширения позволяют использовать любой gmail расширенный поиск для фильтрации сообщений. Таким образом вы можете ограничить загрузку соответствующими сообщениями или исключить некоторые сообщения, которые вам не нужны.

mail.uid('search', None, 'X-GM-RAW', 
       'has:attachment filename:pdf in:inbox -label:parsed'))

Вышеупомянутый поиск сообщений с вложениями PDF в INBOX не помечен как "разобранный".

Некоторые советы:

  • пометьте те сообщения, которые вы уже проанализировали, поэтому вам не нужно их снова брать (в приведенном выше примере используется фильтр -label: parsed).
  • всегда используйте версию uid вместо стандартных последовательных идентификаторов (вы уже это делаете)
  • К сожалению, MIME беспорядочен: есть много клиентов, которые делают странные (или просто неправильные) вещи. Вы можете попытаться загрузить и проанализировать только заголовки, но стоит ли беспокоиться?

[править]

Если вы помечаете сообщение после его разбора, вы можете пропустить уже разобранные сообщения. Это должно быть достаточно разумным, чтобы отслеживать ваш почтовый ящик класса.

Возможно, вы живете в уголке мира, где пропускная способность Интернета дороже, чем время программиста; в этом случае вы можете получить только заголовки и искать "Content-disposition" == "attachment; filename = somefilename.ext".

Ответ 3

A FETCH элемента данных сообщения RFC822 функционально эквивалентен BODY[]. IMAP4 поддерживает другие элементы данных сообщений, перечисленные в разделе раздел 6.4.5 RFC 3501.

Попробуйте запросить другой набор элементов данных сообщений, чтобы получить необходимую информацию. Например, вы можете попробовать RFC822.HEADER или, возможно, BODY.PEEK[MIME].

Ответ 4

Старый вопрос, но просто хотел поделиться с этим решением, которое я придумал сегодня. Ищет все электронные письма с вложениями и выводит uid, отправитель, тему и форматированный список вложений. Отредактированный соответствующий код, чтобы показать, как форматировать BODYSTRUCTURE:

    data   = mailobj.uid('fetch', mail_uid, '(BODYSTRUCTURE)')[1]
    struct = data[0].split()        
    list   = []                     #holds list of attachment filenames

    for j, k in enumerate(struct):
        if k == '("FILENAME"':
            count = 1
            val = struct[j + count]
            while val[-3] != '"':
                count += 1
                val += " " + struct[j + count]
            list.append(val[1:-3])
        elif k == '"FILENAME"':
            count = 1
            val = struct[j + count]
            while val[-1] != '"':
                count += 1
                val += " " + struct[j + count]
            list.append(val[1:-1])

Я также опубликовал его на GitHub.