web-dev-qa-db-fra.com

Obtenir une pièce jointe à un objet fichier python

J'ai un objet de message en plusieurs parties et je souhaite convertir la pièce jointe de ce message en objet de fichier python. Est-ce possible? Si cela est possible, quelle méthode ou classe en Python je devrais étudier pour effectuer une telle tâche?

21
Joshua Partogi

Je ne comprends pas vraiment ce que vous entendez par "objet de message de messagerie multiple". Voulez-vous dire un objet appartenant à la classe email.message.Message ?

Si c'est ce que vous voulez dire, c'est simple. Sur un message en plusieurs parties, la méthode get_payload renvoie une liste d'éléments de message (chacun étant lui-même un objet Message). Vous pouvez parcourir ces parties et examiner leurs propriétés: par exemple, la méthode get_content_type renvoie le type MIME de la partie et la méthode get_filename renvoie le nom de fichier de la partie (le cas échéant). Ensuite, lorsque vous avez trouvé la bonne partie du message, vous pouvez appeler get_payload(decode=True) pour obtenir le contenu décodé.

>>> import email
>>> msg = email.message_from_file(open('message.txt'))
>>> len(msg.get_payload())
2
>>> attachment = msg.get_payload()[1]
>>> attachment.get_content_type()
'image/png'
>>> open('attachment.png', 'wb').write(attachment.get_payload(decode=True))

Si vous extrayez par programme les pièces jointes des courriels que vous avez reçus, vous voudrez peut-être prendre des précautions contre les virus et les chevaux de Troie. En particulier, vous ne devriez probablement extraire que les pièces jointes dont les types MIME, vous le savez, sont sûrs, et vous voulez probablement choisir votre propre nom de fichier ou au moins nettoyer le résultat de get_filename.

54
Gareth Rees

Voici la solution qui fonctionne, les messages sont sous forme de serveur IMAP

self.imap.select()
typ, data = self.imap.uid('SEARCH', 'ALL')
msgs = data[0].split()
print "Found {0} msgs".format(len(msgs))

for uid in msgs:
    typ, s = self.imap.uid('FETCH', uid, '(RFC822)')
    mail = email.message_from_string(s[0][1])

    print "From: {0}, Subject: {1}, Date: {2}\n".format(mail["From"], mail["Subject"], mail["Date"])

    if mail.is_multipart():
        print 'multipart'
        for part in mail.walk():
            ctype = part.get_content_type()
            if ctype in ['image/jpeg', 'image/png']:
                open(part.get_filename(), 'wb').write(part.get_payload(decode=True))
14
pma_

En fait, en utilisant email.EmailMessage API _ (à ne pas confondre avec l'ancien API.mail.Message ) maintenant suggéré, il est assez facile de:

  1. Itérer sur tous les éléments du message et sélectionner uniquement les pièces jointes 

  2. Itérer sur les pièces jointes seulement

Supposons que votre message soit stocké sous forme de contenu d'octet dans une variable d'enveloppe 

Solution n ° 1:

import email
from email.message import EmailMessage

email_message: EmailMessage = email.message_from_bytes(envelope, _class=EmailMessage)

for email_message_part in email_message.walk():
    if email_message.is_attachment():
        # Do something with your attachment

Solution n ° 2: (préférable car vous n'avez pas besoin de parcourir d'autres parties de votre objet message)

import email
from email.message import EmailMessage

email_message: EmailMessage = email.message_from_bytes(envelope, _class=EmailMessage)

for email_message_attachment in email_message.iter_attachments():
        # Do something with your attachment

Quelques choses à noter:

  1. Nous disons explicitement d'utiliser la nouvelle classe EmailMessage dans notre méthode de lecture d'octet via le paramètre _class=EmailMessage
  2. Vous pouvez lire votre message électronique (enveloppe) à partir de sources telles que objet de type octet, objet de fichier binaire ou chaîne grâce aux méthodes intégrées de message.Parser API
0
Jakub Pastuszuk