# `email.parser` : analyser des e-mails

Code source : Lib/email/parser.py

Les instances de messages peuvent être créées de deux façons : elles peuvent être créées de toutes pièces en créant un objet `EmailMessage`, en ajoutant des en-têtes en utilisant l'interface de dictionnaire, et en ajoutant un ou plusieurs corps de message en utilisant `set_content()` et les méthodes associées, ou elles peuvent être créées en analysant une représentation sérialisée de l'e-mail.

Le paquet `email` fournit un analyseur standard qui comprend la plupart des structures de documents de courrier électronique, y compris les documents MIME. Vous pouvez passer à l'analyseur un objet bytes, chaîne ou fichier, et l'analyseur vous renverra l'instance racine `EmailMessage` de la structure de l'objet. Pour les messages simples non MIME, la charge utile de cet objet racine sera probablement une chaîne contenant le texte du message. Pour les messages MIME, la méthode `is_multipart()` de l'objet racine renvoie `True`, et les sous-parties sont accessibles via les méthodes de manipulation de la charge utile, telles que `get_body()`, `iter_parts()` et `walk()`.

Il existe en fait deux interfaces d'analyseur disponibles, l'API `Parser` et l'API incrémentale `FeedParser`. L'API `Parser` est plus utile si vous avez le texte entier du message en mémoire ou si le message entier réside dans un fichier sur le système de fichiers. `FeedParser` est plus appropriée lorsque vous lisez le message à partir d'un flux qui peut bloquer en attente d'une entrée supplémentaire (comme la lecture d'un message électronique à partir d'un connecteur réseau). `FeedParser` peut consommer et analyser le message de manière incrémentielle et ne renvoie l'objet racine que lorsque vous fermez l'analyseur.

Note that the parser can be extended in limited ways, and of course you can implement your own parser completely from scratch. All of the logic that connects the `email` package's bundled parser and the `EmailMessage` class is embodied in the `Policy` class, so a custom parser can create message object trees any way it finds necessary by implementing custom versions of the appropriate `Policy` methods.

## API FeedParser

`BytesFeedParser`, importée du module `email.feedparser`, fournit une API propice à l'analyse incrémentielle des messages électroniques, adaptée à la lecture du texte d'un message électronique à partir d'une source qui peut bloquer (comme un connecteur). `BytesFeedParser` peut bien sûr être utilisée pour analyser un message électronique entièrement contenu dans un objet octets-compatible, une chaîne ou un fichier, mais l'API `BytesParser` peut être plus pratique dans ces utilisations. La sémantique et les résultats des deux API d'analyseurs sont identiques.

L'API de `BytesFeedParser` est simple ; vous créez une instance, l'alimentez d'une suite d'octets jusqu'à ce qu'il n'y en ait plus pour l'alimenter, puis fermez l'analyseur pour récupérer l'objet message racine. `BytesFeedParser` est extrêmement précise lors de l'analyse des messages conformes aux normes, et elle fait un très bon travail d'analyse des messages non conformes, fournissant des informations sur ce qu'elle considère comme non approprié dans un message. Elle remplit l'attribut `defects` d'un objet message avec une liste de tous les problèmes trouvés dans un message. Voir le module `email.errors` pour la liste des défauts qu'elle peut trouver.

Voici l’API de `BytesFeedParser` :

class email.parser.BytesFeedParser(_factory=None, *, policy=policy.compat32)

  Crée une instance `BytesFeedParser`. _factory est un appelable facultatif sans argument ; s'il n'est pas spécifié, elle utilise la `message_factory` de la policy. Elle appelle _factory chaque fois qu'un nouvel objet de message est nécessaire.

  Si policy est spécifiée, elle utilise les règles spécifiées pour mettre à jour la représentation du message. Si policy n'est pas définie, elle utilise la stratégie `compat32`, qui maintient la rétrocompatibilité avec la version Python 3.2 du paquet de messagerie et fournit `Message` comme usine par défaut. Toutes les autres stratégies fournissent `EmailMessage` comme _factory par défaut. Pour plus d'informations sur ce que policy régit, consultez la documentation `policy`.

  Remarque : Le paramètre nommé « policy » doit toujours être spécifié ; La valeur par défaut deviendra `email.policy.default` dans une future version de Python.

  Nouveau dans la version 3.2.

  Modifié dans la version 3.3: ajout du paramètre nommé policy.

  Modifié dans la version 3.6: _factory utilise par défaut la politique `message_factory`.

  feed(data)

    Alimente l'analyseur avec plus de données. data doit être un objet octets-compatible contenant une ou plusieurs lignes. Les lignes peuvent être partielles et l'analyseur assemble correctement ces lignes partielles. Les lignes peuvent avoir l'une des trois fins de ligne courantes : retour chariot, nouvelle ligne ou retour chariot et nouvelle ligne (elles peuvent même être mélangées).

  close()

    Termine l'analyse de toutes les données précédemment alimentées et renvoie l'objet message racine. Ce qui se passe si `feed()` est appelée après l'appel de cette méthode n'est pas défini.

class email.parser.FeedParser(_factory=None, *, policy=policy.compat32)

  Fonctionne comme `BytesFeedParser` sauf que l'entrée de la méthode `feed()` doit être une chaîne. Ceci est d'une utilité limitée, car la seule façon pour qu'un tel message soit valide est qu'il ne contienne que du texte ASCII ou, si `utf8` vaut `True`, aucun binaire en pièce jointe.

  Modifié dans la version 3.3: ajout du paramètre nommé policy.

## API de Parser

La classe `BytesParser`, importée du module `email.parser`, fournit une API qui peut être utilisée pour analyser un message lorsque le contenu complet du message est disponible dans un objet octets-compatible ou un fichier. Le module `email.parser` fournit également `Parser` pour l'analyse des chaînes et des analyseurs d'en-tête uniquement, `BytesHeaderParser` et `HeaderParser`, qui peuvent être utilisés si vous ne vous intéressez qu'aux en-têtes du message. `BytesHeaderParser` et `HeaderParser` peuvent être beaucoup plus rapides dans ces situations, car ils n'essaient pas d'analyser le corps du message.

class email.parser.BytesParser(_class=None, *, policy=policy.compat32)

  Crée une instance `BytesParser`. Les arguments _class et policy ont la même signification et la même sémantique que les arguments _factory et policy de `BytesFeedParser`.

  Remarque : Le paramètre nommé « policy » doit toujours être spécifié ; La valeur par défaut deviendra `email.policy.default` dans une future version de Python.

  Modifié dans la version 3.3: suppression de l'argument strict qui était obsolète dans 2.4. Ajout du paramètre nommé policy.

  Modifié dans la version 3.6: _class utilise par défaut la politique `message_factory`.

  parse(fp, headersonly=False)

    Lit toutes les données de l'objet de type fichier binaire fp, analyse les octets résultants et renvoie l'objet message. fp doit prendre en charge les méthodes `readline()` et `read()`.

    Les octets contenus dans fp doivent être formatés comme un bloc d'en-têtes de style conforme à la RFC 5322 (ou, si `utf8` est `True`, à la RFC 6532), éventuellement précédés d'un en-tête d'enveloppe. Le bloc d'en-têtes se termine soit par la fin des données, soit par une ligne blanche. Après le bloc d'en-têtes se trouve le corps du message (qui peut contenir des sous-parties codées MIME, y compris des sous-parties avec un Content-Transfer-Encoding de `8bit`).

    headersonly est un indicateur facultatif spécifiant s'il faut arrêter l'analyse après avoir lu les en-têtes ou non. La valeur par défaut est `False`, ce qui signifie qu'il analyse tout le contenu du fichier.

  parsebytes(bytes, headersonly=False)

    Semblable à la méthode `parse()`, sauf qu'elle prend un objet octets-compatible au lieu d'un objet de type fichier. Appeler cette méthode sur un objet octets-compatible équivaut à envelopper bytes dans une instance `BytesIO` d'abord et à appeler `parse()`.

    L'utilisation de l'option headersonly est identique à son utilisation dans la méthode `parse()`.

  Nouveau dans la version 3.2.

class email.parser.BytesHeaderParser(_class=None, *, policy=policy.compat32)

  Exactement comme `BytesParser`, sauf que headersonly par défaut est `True`.

  Nouveau dans la version 3.3.

class email.parser.Parser(_class=None, *, policy=policy.compat32)

  Cette classe est semblable à `BytesParser`, mais elle accepte une chaîne en entrée.

  Modifié dans la version 3.3: suppression de l'argument strict. Ajout de l'argument nommé policy.

  Modifié dans la version 3.6: _class utilise par défaut la politique `message_factory`.

  parse(fp, headersonly=False)

    Lit toutes les données de l'objet de type fichier en mode texte fp, analyse le texte résultant et renvoie l'objet message racine. fp doit prendre en charge les méthodes `readline()` et `read()` sur les objets de type fichier.

    Outre l'exigence du mode texte, cette méthode fonctionne comme `BytesParser.parse()`.

  parsestr(text, headersonly=False)

    Similaire à la méthode `parse()`, sauf qu'elle prend un objet chaîne au lieu d'un objet de type fichier. Appeler cette méthode sur une chaîne équivaut à envelopper text dans une instance `StringIO` d'abord et à appeler `parse()`.

    L'utilisation de l'option headersonly est identique à son utilisation dans la méthode `parse()`.

class email.parser.HeaderParser(_class=None, *, policy=policy.compat32)

  Exactement comme `Parser`, sauf que headersonly par défaut est `True`.

Étant donné que la création d'une structure d'objet message à partir d'une chaîne ou d'un objet fichier est une tâche très courante, quatre fonctions sont fournies par commodité. Elles sont disponibles dans l'espace de noms de paquet de niveau supérieur `email`.

email.message_from_bytes(s, _class=None, *, policy=policy.compat32)

  Renvoie une structure d'objet message à partir d'un objet octets-compatible. C'est équivalent à `BytesParser().parsebytes(s)`. _class et policy (facultatifs) sont interprétés comme pour le constructeur de classe `BytesParser`.

  Nouveau dans la version 3.2.

  Modifié dans la version 3.3: suppression de l'argument strict. Ajout de l'argument nommé policy.

email.message_from_binary_file(fp, _class=None, *, policy=policy.compat32)

  Renvoie une arborescence d'objets message à partir d'un objet fichier binaire ouvert. C'est équivalent à `BytesParser().parse(fp)`. _class et policy sont interprétés comme pour le constructeur de classe `BytesParser`.

  Nouveau dans la version 3.2.

  Modifié dans la version 3.3: suppression de l'argument strict. Ajout de l'argument nommé policy.

email.message_from_string(s, _class=None, *, policy=policy.compat32)

  Renvoie une structure d'objet message à partir d'une chaîne. C'est équivalent à `Parser().parsestr(s)`. _class et policy sont interprétés comme avec le constructeur de classe `Parser`.

  Modifié dans la version 3.3: suppression de l'argument strict. Ajout de l'argument nommé policy.

email.message_from_file(fp, _class=None, *, policy=policy.compat32)

  Renvoie une arborescence de structures d'objets messages à partir d'un objet fichier ouvert. C'est équivalent à `Parser().parse(fp)`. _class et policy sont interprétés comme avec le constructeur de classe `Parser`.

  Modifié dans la version 3.3: suppression de l'argument strict. Ajout de l'argument nommé policy.

  Modifié dans la version 3.6: _class utilise par défaut la politique `message_factory`.

Voici un exemple d'utilisation `message_from_bytes()` dans une invite Python interactive :

    >>> import email
    >>> msg = email.message_from_bytes(myBytes)

## Notes complémentaires

Voici des remarques sur la sémantique d'analyse :

- La plupart des messages de type non-multipart sont analysés comme un seul objet de message avec une charge utile de type chaîne. Ces objets renvoient `False` pour `is_multipart()` et `iter_parts()` donne une liste vide.

- Tous les messages de type multipart sont analysés comme un objet de message conteneur avec une liste d'objets de sous-messages pour leur charge utile. Le message du conteneur externe renvoie `True` pour `is_multipart()` et `iter_parts()` donne une liste de sous-parties.

- La plupart des messages avec un type de contenu de message/* (tels que message/delivery-status et message/rfc822) sont également analysés en tant qu'objet conteneur contenant une charge utile de type « liste de longueur 1 ». Leur méthode `is_multipart()` renvoie `True`. L'élément unique généré par `iter_parts()` est un objet sous-message.

- Certains messages non conformes aux normes peuvent ne pas être cohérents en interne quant à multipart. De tels messages peuvent avoir un en-tête Content-Type de type multipart, mais leur méthode `is_multipart()` peut renvoyer `False`. Si de tels messages ont été analysés avec la `FeedParser`, ils auront une instance de la classe `MultipartInvariantViolationDefect` dans leur liste d'attributs defects. Voir `email.errors` pour plus de détails.