"email.headerregistry": Custom Header Objects
*********************************************

**Code source :** Lib/email/headerregistry.py

======================================================================

Ajouté dans la version 3.6: [1]

Les en-têtes sont représentés par des sous-classes personnalisées de
"str". La classe particulière utilisée pour représenter un en-tête
donné est déterminée par "header_factory" de la "policy" en vigueur
lorsque les en-têtes sont créés. Cette section documente la
"header_factory" particulière implémentée par le paquet de messagerie
pour la gestion des messages électroniques conformes à la **RFC
5322**, qui fournit non seulement des objets d'en-tête personnalisés
pour différents types d'en-tête, mais fournit également un mécanisme
d'extension permettant aux applications d'ajouter leurs propres types
d'en-tête personnalisés.

Lors de l'utilisation de l'un des objets de définition de politique
dérivés de "EmailPolicy", tous les en-têtes sont produits par
"HeaderRegistry" et ont "BaseHeader" comme dernière classe mère.
Chaque classe d'en-tête a une classe mère supplémentaire qui est
déterminée par le type de l'en-tête. Par exemple, de nombreux en-têtes
ont la classe "UnstructuredHeader" comme autre classe mère. La
deuxième classe spécialisée pour un en-tête est déterminée par le nom
de l'en-tête, en utilisant un tableau de recherche stocké dans
"HeaderRegistry". Tout cela est géré de manière transparente pour le
programme d'application typique, mais des interfaces sont fournies
pour modifier le comportement par défaut pour une utilisation par des
applications plus complexes.

Les sections ci-dessous documentent d'abord les classes mères d'en-
tête et leurs attributs, suivies de l'API pour modifier le
comportement de "HeaderRegistry", et enfin les classes de gestion
utilisées pour représenter les données analysées à partir d'en-têtes
structurés.

class email.headerregistry.BaseHeader(name, value)

   *name* et *value* sont passés à "BaseHeader" à partir de l'appel
   "header_factory". La valeur de chaîne de tout objet d'en-tête est
   la *value* entièrement décodée en Unicode.

   Cette classe mère définit les propriétés en lecture seule suivantes
   :

   name

      Nom de l'en-tête (la partie du champ avant le ":"). C'est
      exactement la valeur passée dans l'appel "header_factory" pour
      *name* ; c'est-à-dire que la casse est préservée.

   defects

      *n*-uplet d'instances "HeaderDefect" signalant tout problème de
      conformité avec les RFC détecté lors de l'analyse. Le paquet
      d'e-mails tente d'être complet en ce qui concerne la détection
      des problèmes de conformité. Voir le module "errors" pour une
      discussion sur les types de défauts qui peuvent être signalés.

   max_count

      Nombre maximum d'en-têtes de ce type pouvant avoir le même
      "name". Une valeur de "None" signifie illimité. La valeur
      "BaseHeader" pour cet attribut est "None" ; les classes d'en-
      tête spécialisées sont censées remplacer cette valeur si
      nécessaire.

   "BaseHeader" fournit également la méthode suivante, qui est appelée
   par le code de la bibliothèque de messagerie et ne doit
   généralement pas être appelée par les programmes d'application :

   fold(*, policy)

      Renvoie une chaîne contenant les caractères "linesep"
      nécessaires pour remettre en forme correctement l'en-tête
      conformément à *policy*. Un "cte_type" de "8bit" est traité
      comme s'il s'agissait de "7bit", car les en-têtes ne peuvent pas
      contenir de données binaires arbitraires. Si "utf8" est "False",
      les données non-ASCII seront encodées selon la **RFC 2047**.

   "BaseHeader" seule ne peut pas être utilisée pour créer un objet d
   'en-tête. Elle définit un protocole avec lequel chaque en-tête
   spécialisé coopère afin de produire l'objet d'en-tête. Plus
   précisément, "BaseHeader" nécessite que la classe spécialisée
   fournisse une "classmethod()" nommée "parse". Cette méthode
   s'appelle comme suit :

      parse(string, kwds)

   "kwds" est un dictionnaire contenant une clé pré-initialisée :
   "defects". "defects" est une liste vide. La méthode d'analyse doit
   ajouter tous les défauts détectés à cette liste. Au retour, le
   dictionnaire "kwds" *doit* contenir des valeurs pour au moins les
   clés "decoded" et "defects". "decoded" doit être la valeur de la
   chaîne pour l'en-tête (c'est-à-dire la valeur de l'en-tête
   entièrement décodée en Unicode). La méthode d'analyse doit supposer
   que *string* peut contenir des parties codées par transfert de
   contenu, mais doit également gérer correctement tous les caractères
   Unicode valides afin de pouvoir analyser les valeurs d'en-tête non
   codées.

   "__new__" de "BaseHeader" crée ensuite l'instance d'en-tête et
   appelle sa méthode "init". La classe spécialisée n'a besoin de
   fournir une méthode "init" que si elle souhaite définir des
   attributs supplémentaires au-delà de ceux fournis par "BaseHeader"
   lui-même. Une telle méthode "init" devrait ressembler à ceci :

      def init(self, /, *args, **kw):
          self._myattr = kw.pop('myattr')
          super().init(*args, **kw)

   Autrement dit, tout ce que la classe spécialisée ajoute au
   dictionnaire "kwds" doit être supprimé et géré, et le contenu
   restant de "kw" (et "args") est passé à la méthode "init" de
   "BaseHeader".

class email.headerregistry.UnstructuredHeader

   Un en-tête « non structuré » est le type d'en-tête par défaut dans
   la **RFC 5322**. Tout en-tête qui n'a pas de syntaxe spécifiée est
   traité comme non structuré. L'exemple classique d'en-tête non
   structuré est l'en-tête *Subject*.

   Dans la **RFC 5322**, un en-tête non structuré est une séquence de
   texte arbitraire dans le jeu de caractères ASCII. **RFC 2047**,
   cependant, possède un mécanisme compatible **RFC 5322** pour
   encoder du texte non-ASCII en tant que caractères ASCII dans une
   valeur d'en-tête. Lorsqu'une *value* contenant des mots encodés est
   passée au constructeur, l'analyseur "UnstructuredHeader" convertit
   ces mots encodés en Unicode, en suivant les règles de la **RFC
   2047** pour le texte non structuré. L'analyseur utilise des
   heuristiques pour tenter de décoder certains mots codés non
   conformes. Des défauts sont enregistrés dans de tels cas, ainsi que
   des défauts pour des problèmes tels que des caractères non valides
   dans les mots codés ou le texte non codé.

   Ce type d'en-tête ne fournit aucun attribut supplémentaire.

class email.headerregistry.DateHeader

   La **RFC 5322** spécifie un format très spécifique pour les dates
   dans les en-têtes de courrier électronique. L'analyseur
   "DateHeader" reconnaît ce format de date, ainsi qu'un certain
   nombre de formes variantes que l'on trouve parfois « dans la nature
   ».

   Ce type d'en-tête fournit les attributs supplémentaires suivants :

   datetime

      Si la valeur d'en-tête peut être reconnue comme une date valide
      d'une forme ou d'une autre, cet attribut contient une instance
      "datetime" représentant cette date. Si le fuseau horaire de la
      date d'entrée est spécifié comme "-0000" (indiquant qu'il est en
      UTC mais ne contient aucune information sur le fuseau horaire
      source), alors "datetime" est une "datetime" naïve. Si un
      décalage de fuseau horaire spécifique est trouvé (y compris
      "+0000"), alors "datetime" contient un "datetime" avisé qui
      utilise "datetime.timezone" pour enregistrer le décalage lié au
      fuseau horaire.

   La valeur "decoded" de l'en-tête est déterminée en formatant le
   "datetime" selon les règles de la **RFC 5322** ; c'est-à-dire
   qu'elle est définie sur :

      email.utils.format_datetime(self.datetime)

   Lors de la création d'un "DateHeader", *value* peut être une
   instance de "datetime". Cela signifie, par exemple, que le code
   suivant est valide et fait ce à quoi on pourrait s'attendre :

      msg['Date'] = datetime(2011, 7, 15, 21)

   Comme il s'agit d'un "datetime" naïf, il est interprété comme un
   horodatage UTC et la valeur résultante a un fuseau horaire de
   "-0000". Il est beaucoup plus utile d'utiliser la fonction
   "localtime()" du module "utils" :

      msg['Date'] = utils.localtime()

   Cet exemple définit l'en-tête de date sur l'heure et la date
   actuelles à l'aide du décalage horaire actuel.

class email.headerregistry.AddressHeader

   Les en-têtes d'adresse sont l'un des types d'en-têtes structurés
   les plus complexes. La classe "AddressHeader" fournit une interface
   générique à n'importe quel en-tête d'adresse.

   Ce type d'en-tête fournit les attributs supplémentaires suivants :

   groups

      *n*-uplet d'objets "Group" encodant les adresses et les groupes
      trouvés dans la valeur d'en-tête. Les adresses qui ne font pas
      partie d'un groupe sont représentées dans cette liste comme des
      "Groups" à adresse unique dont "display_name" est "None".

   addresses

      *n*-uplet d'objets "Address" encodant toutes les adresses
      individuelles à partir de la valeur d'en-tête. Si la valeur d
      'en-tête contient des groupes, les adresses individuelles du
      groupe sont incluses dans la liste au point où le groupe
      apparaît dans la valeur (c'est-à-dire que la liste d'adresses
      est « aplatie » en une liste unidimensionnelle).

   La valeur "decoded" de l'en-tête a tous les mots codés décodés en
   Unicode. Les noms de domaine encodés en "idna" sont également
   décodés en Unicode. La valeur "decoded" est définie en joignant la
   valeur "str" des éléments de l'attribut "groups" avec "', '".

   Une liste d'objets "Address" et "Group" dans n'importe quelle
   combinaison peut être utilisée pour définir la valeur d'un en-tête
   d'adresse. Les objets "Group" dont le "display_name" est "None"
   sont interprétés comme des adresses uniques, ce qui permet de
   copier une liste d'adresses avec des groupes intacts en utilisant
   la liste obtenue à partir de l'attribut "groups" de l'en-tête
   source.

class email.headerregistry.SingleAddressHeader

   Sous-classe de "AddressHeader" qui ajoute un attribut
   supplémentaire :

   address

      Adresse unique codée par la valeur d'en-tête. Si la valeur d'en-
      tête contient en fait plus d'une adresse (ce qui serait une
      violation de la RFC sous la valeur par défaut "policy"), l'accès
      à cet attribut lève une "ValueError".

La plupart des classes ci-dessus ont également une variante "Unique"
(par exemple, "UniqueUnstructuredHeader"). La seule différence est que
dans la variante "Unique", "max_count" est définie sur 1.

class email.headerregistry.MIMEVersionHeader

   Il n'y a vraiment qu'une seule valeur valide pour l'en-tête *MIME-
   Version*, et c'est "1.0". Au cas où, cette classe d'en-tête prend
   en charge d'autres numéros de version valides. Si un numéro de
   version a une valeur valide selon la **RFC 2045**, alors l'objet d
   'en-tête a des valeurs autres que "None" pour les attributs
   suivants :

   version

      Numéro de version sous forme de chaîne, sans espaces ni
      commentaires.

   major

      Numéro de version majeure sous forme d'entier

   minor

      Numéro de version mineure sous forme d'entier

class email.headerregistry.ParameterizedMIMEHeader

   Les en-têtes MIME commencent tous par le préfixe "'Content-'".
   Chaque en-tête spécifique a une certaine valeur, décrite par la
   classe de cet en-tête. Certains peuvent également prendre une liste
   de paramètres supplémentaires, qui ont un format commun. Cette
   classe sert de base à tous les en-têtes MIME qui prennent des
   paramètres.

   params

      Dictionnaire de correspondance entre les noms de paramètres et
      leurs valeurs.

class email.headerregistry.ContentTypeHeader

   Classe "ParameterizedMIMEHeader" qui gère l'en-tête *Content-Type*.

   content_type

      Chaîne de type de contenu, sous la forme "maintype/subtype".

   maintype

   subtype

class email.headerregistry.ContentDispositionHeader

   Classe "ParameterizedMIMEHeader" qui gère l'en-tête *Content-
   Disposition*.

   content_disposition

      "inline" et "attachment" sont les seules valeurs valides
      couramment utilisées.

class email.headerregistry.ContentTransferEncoding

   Gère l'en-tête *Content-Transfer-Encoding*.

   cte

      Les valeurs valides sont "7bit", "8bit", "base64" et "quoted-
      printable". Voir la **RFC 2045** pour plus d'informations.

class email.headerregistry.HeaderRegistry(base_class=BaseHeader, default_class=UnstructuredHeader, use_default_map=True)

   This is the factory used by "EmailPolicy" by default.
   "HeaderRegistry" builds the class used to create a header instance
   dynamically, using *base_class* and a specialized class retrieved
   from a registry that it holds.  When a given header name does not
   appear in the registry, the class specified by *default_class* is
   used as the specialized class.  When *use_default_map* is "True"
   (the default), the standard mapping of header names to classes is
   copied in to the registry during initialization.  *base_class* is
   always the last class in the generated class's "__bases__" list.

   Les correspondances par défaut sont :

      subject:
         UniqueUnstructuredHeader

      date:
         UniqueDateHeader

      resent-date:
         DateHeader

      orig-date:
         UniqueDateHeader

      sender:
         UniqueSingleAddressHeader

      resent-sender:
         SingleAddressHeader

      to:
         UniqueAddressHeader

      resent-to:
         AddressHeader

      cc:
         UniqueAddressHeader

      resent-cc:
         AddressHeader

      bcc:
         UniqueAddressHeader

      resent-bcc:
         AddressHeader

      from:
         UniqueAddressHeader

      resent-from:
         AddressHeader

      reply-to:
         UniqueAddressHeader

      mime-version:
         MIMEVersionHeader

      content-type:
         ContentTypeHeader

      content-disposition:
         ContentDispositionHeader

      content-transfer-encoding:
         ContentTransferEncodingHeader

      message-id:
         MessageIDHeader

   "HeaderRegistry" a les méthodes suivantes :

   map_to_type(self, name, cls)

      *name* est le nom de l'en-tête à faire correspondre. Il est
      converti en minuscules dans le registre. *cls* est la classe
      spécialisée à utiliser, avec *base_class*, pour créer la classe
      utilisée pour instancier les en-têtes qui correspondent à
      *name*.

   __getitem__(name)

      Construit et renvoie une classe pour gérer la création d'un en-
      tête *name*.

   __call__(name, value)

      Récupère l'en-tête spécialisé associé à *name* du registre (en
      utilisant *default_class* si *name* n'apparaît pas dans le
      registre) et le compose avec *base_class* pour produire une
      classe, appelle le constructeur de la classe construite, en lui
      passant la même liste d'arguments, et renvoie enfin l'instance
      de classe ainsi créée.

Les classes suivantes sont les classes utilisées pour représenter les
données analysées à partir d'en-têtes structurés et peuvent, en
général, être utilisées par un programme d'application pour construire
des valeurs structurées à affecter à des en-têtes spécifiques.

class email.headerregistry.Address(display_name='', username='', domain='', addr_spec=None)

   Classe utilisée pour représenter une adresse e-mail. La forme
   générale d'une adresse est :

      [display_name] <username@domain>

   ou :

      username@domain

   où chaque partie doit se conformer à des règles de syntaxe
   spécifiques énoncées dans la **RFC 5322**.

   Pour plus de commodité, *addr_spec* peut être spécifié à la place
   de *username* et *domain*, *username* et *domain* sont alors
   analysés à partir de *addr_spec*. Une *addr_spec* doit être une
   chaîne correctement entre guillemets RFC ; si ce n'est pas le cas,
   "Address" lève une erreur. Les caractères Unicode sont autorisés et
   sont encodés proprement lors de la sérialisation. Cependant, selon
   les RFC, l’Unicode n'est *pas* autorisé dans la partie nom
   d'utilisateur de l'adresse.

   display_name

      Partie du nom d'affichage de l'adresse, le cas échéant, avec
      toutes les citations supprimées. Si l'adresse n'a pas de nom
      d'affichage, cet attribut est une chaîne vide.

   username

      Partie "username" de l'adresse, sans guillemets.

   domain

      Partie "domain" de l'adresse.

   addr_spec

      Partie "username@domain" de l'adresse, correctement citée pour
      une utilisation en tant qu'adresse nue (la deuxième forme
      illustrée ci-dessus). Cet attribut n'est pas modifiable.

   __str__()

      La valeur "str" de l'objet est l'adresse entre guillemets selon
      les règles de la **RFC 5322**, mais sans encodage de contenu
      pour les caractères non-ASCII.

   Pour prendre en charge SMTP (**RFC 5321**), "Address" gère un cas
   particulier : si "username" et "domain" sont tous deux la chaîne
   vide (ou "None"), alors la valeur de chaîne de "Address" est "<>".

class email.headerregistry.Group(display_name=None, addresses=None)

   Classe utilisée pour représenter un groupe d'adresses. La forme
   générale d'un groupe d'adresses est :

      display_name: [address-list];

   Pour faciliter le traitement des listes d'adresses composées d'un
   mélange de groupes et d'adresses uniques, un "Group" peut également
   être utilisé pour représenter des adresses uniques qui ne font pas
   partie d'un groupe en définissant *display_name* sur "None" et en
   fournissant une liste de l'adresse unique sous la forme *adresses*.

   display_name

      "display_name" du groupe. Si c'est "None" et qu'il y a
      exactement une "Adress" dans "adresses", alors le "Group"
      représente une seule adresse qui n'est pas dans un groupe.

   addresses

      *n*-uplet éventuellement vide d'objets "Address" représentant
      les adresses du groupe.

   __str__()

      La valeur "str" d'un "Group" est formatée selon la **RFC 5322**,
      mais sans encodage de contenu pour les caractères non-ASCII. Si
      "display_name" est "None" et qu'il y a une seule "Address" dans
      la liste "addresses", la valeur "str" est la même que la "str"
      de cette seule "Adress".

-[ Notes ]-

[1] Ajouté à l'origine dans 3.3 en tant que *paquet provisoire*
