web-dev-qa-db-fra.com

python imaplib pour obtenir les titres des sujets de la boîte de réception gmail et le nom de l'expéditeur

J'utilise pythons imaplib pour me connecter à mon compte gmail. Je souhaite récupérer les 15 premiers messages (non lus ou lus, peu importe) et afficher uniquement les sujets et le nom de l'expéditeur (ou l'adresse), mais je ne sais pas comment afficher le contenu de la boîte de réception.

Voici mon code jusqu'à présent (connexion réussie)

import imaplib

mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login('[email protected]', 'somecrazypassword')
mail.list()
mail.select('inbox')

#need to add some stuff in here

mail.logout()

Je crois que cela devrait être assez simple, je ne suis tout simplement pas assez familier avec les commandes de la bibliothèque imaplib. Toute aide serait appréciée ...

UPDATE grâce à Julian je peux parcourir chaque message et récupérer l'intégralité du contenu avec:

typ, data = mail.search(None, 'ALL')
for num in data[0].split():
   typ, data = mail.fetch(num, '(RFC822)')
   print 'Message %s\n%s\n' % (num, data[0][1])
mail.close()

mais je veux juste le sujet et l'expéditeur. Existe-t-il une commande imaplib pour ces éléments ou devrai-je analyser l'intégralité du contenu des données [0] [1] pour le texte: Objet et Expéditeur?

UPDATE OK, le sujet et l'expéditeur fonctionnent mais l'itération (1, 15) se fait par ordre de descente en me montrant apparemment les messages les plus anciens en premier. Comment puis-je changer cela? J'ai essayé de faire ça:

for i in range( len(data[0])-15, len(data[0]) ):
     print data

mais cela me donne juste None pour les 15 itérations ... des idées? J'ai également essayé mail.sort('REVERSE DATE', 'UTF-8', 'ALL') mais gmail ne prend pas en charge la fonction .sort ()

MISE À JOUR Compris un moyen de le faire:

#....^other code is the same as above except need to import email module
mail.select('inbox')
typ, data = mail.search(None, 'ALL')
ids = data[0]
id_list = ids.split()
#get the most recent email id
latest_email_id = int( id_list[-1] )

#iterate through 15 messages in decending order starting with latest_email_id
#the '-1' dictates reverse looping order
for i in range( latest_email_id, latest_email_id-15, -1 ):
   typ, data = mail.fetch( i, '(RFC822)' )

   for response_part in data:
      if isinstance(response_part, Tuple):
          msg = email.message_from_string(response_part[1])
          varSubject = msg['subject']
          varFrom = msg['from']

   #remove the brackets around the sender email address
   varFrom = varFrom.replace('<', '')
   varFrom = varFrom.replace('>', '')

   #add Ellipsis (...) if subject length is greater than 35 characters
   if len( varSubject ) > 35:
      varSubject = varSubject[0:32] + '...'

   print '[' + varFrom.split()[-1] + '] ' + varSubject

cela me donne le dernier 15 message et l'adresse de l'expéditeur dans l'ordre décent comme demandé! Merci à tous ceux qui ont aidé!

22
sadmicrowave
    c.select('INBOX', readonly=True)

    for i in range(1, 30):
        typ, msg_data = c.fetch(str(i), '(RFC822)')
        for response_part in msg_data:
            if isinstance(response_part, Tuple):
                msg = email.message_from_string(response_part[1])
                for header in [ 'subject', 'to', 'from' ]:
                    print '%-8s: %s' % (header.upper(), msg[header])

Cela devrait vous donner une idée sur la façon de récupérer le sujet et de partir?

15
Torxed

Pour ceux qui cherchent à vérifier le courrier et à analyser les en-têtes, voici ce que j'ai utilisé:

def parse_header(str_after, checkli_name, mailbox) :
    #typ, data = m.search(None,'SENTON', str_after)
    print mailbox
    m.SELECT(mailbox)
    date = (datetime.date.today() - datetime.timedelta(1)).strftime("%d-%b-%Y")
    #date = (datetime.date.today().strftime("%d-%b-%Y"))
    #date = "23-Jul-2012"

    print date
    result, data = m.uid('search', None, '(SENTON %s)' % date)
    print data

    doneli = []
    for latest_email_uid in data[0].split():
        print latest_email_uid
        result, data = m.uid('fetch', latest_email_uid, '(RFC822)')
        raw_email = data[0][1]

        import email
        email_message = email.message_from_string(raw_email)
        print email_message['To']
        print email_message['Subject']
        print email.utils.parseaddr(email_message['From'])
        print email_message.items() # print all headers
5
namit

C'était ma solution pour obtenir les informations utiles des e-mails:

import datetime
import email
import imaplib
import mailbox


EMAIL_ACCOUNT = "[email protected]"
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
5
Edward Chapman

Je cherchais un script simple prêt à l'emploi pour répertorier la dernière boîte de réception via IMAP sans trier tous les messages. Les informations ici sont utiles, bien que bricolage et manquent de certains aspects. Première, IMAP4.select renvoie le nombre de messages. Deuxièmement, le décodage de l'en-tête du sujet n'est pas simple.

#! /usr/bin/env python
# -*- coding: utf-8 -*-


import imaplib
import email
from email.header import decode_header
import HTMLParser


# to unescape xml entities
_parser = HTMLParser.HTMLParser()

def decodeHeader(value):
  if value.startswith('"=?'):
    value = value.replace('"', '')

  value, encoding = decode_header(value)[0]
  if encoding:
    value = value.decode(encoding)

  return _parser.unescape(value)

def listLastInbox(top = 4):
  mailbox = imaplib.IMAP4_SSL('imap.gmail.com')
  mailbox.login('[email protected]', 'somecrazypassword')

  selected = mailbox.select('INBOX')
  assert selected[0] == 'OK'
  messageCount = int(selected[1][0])

  for i in range(messageCount, messageCount - top, -1):
    reponse = mailbox.fetch(str(i), '(RFC822)')[1]
    for part in reponse:
      if isinstance(part, Tuple):
        message = email.message_from_string(part[1])
        yield {h: decodeHeader(message[h]) for h in ('subject', 'from', 'date')}

  mailbox.logout()


if __name__ == '__main__':
  for message in listLastInbox():
    print '-' * 40
    for h, v in message.items():
      print u'{0:8s}: {1}'.format(h.upper(), v)
3
saaj

BODY récupère presque tout et marque le message comme lu. BODY[<parts>] Obtient uniquement ces pièces. BODY.PEEK[<parts>] Obtient les mêmes parties, mais ne marque pas le message comme lu. <parts> Peut être HEADER ou TEXT ou HEADER.FIELDS (<list of fields>) ou HEADER.FIELDS.NOT (<list of fields>)

Voici ce que j'utilise: typ, data = connection.fetch(message_num_s, b'(BODY.PEEK[HEADER.FIELDS (SUBJECT FROM)])')

"

def safe_encode(seq):
    if seq not in (list,Tuple):
        seq = [seq]
    for i in seq:
        if isinstance(i, (int,float)):
            yield str(i).encode()
        Elif isinstance(i, str):
            yield i.encode()
        Elif isinstance(i, bytes):
            yield i
        else:
            raise ValueError

def fetch_fields(connection, message_num, field_s):
    """Fetch just the fields we care about. Parse them into a dict"""
    if isinstance(field_s, (list,Tuple)):
        field_s = b' '.join(safe_encode(field_s))
    else:
        field_s = Tuple(safe_encode(field_s))[0]

    message_num = Tuple(safe_encode(message_num))[0]

    typ, data = connection.fetch(message_num, b'(BODY.PEEK[HEADER.FIELDS (%s)])'%(field_s.upper()))
    if typ != 'OK':
        return typ, data  #change this to an exception if you'd rather

    items={}
    lastkey = None
    for line in data[0][1].splitlines():
        if b':' in line:
            lastkey, value = line.strip().split(b':', 1)
            lastkey = lastkey.capitalize()
            #not all servers capitalize the same, and some just leave it
            #as however it arrived from some other mail server.

            items[lastkey]=value
        else:
            #subject was so long it ran onto the next line, luckily it didn't have a ':' in it so its easy to recognize.
            items[lastkey]+=line
            #print(items[lastkey])
    return typ, items
`

Vous le déposez dans votre exemple de code: en remplaçant l'appel à 'mail.fetch ()' par fetch_fields(mail, i, 'SUBJECT FROM') ou fetch_fields(mail, i, ('SUBJECT' 'FROM'))

0
hbregalad