# `email.parser`: Analizar mensajes de correo electrónico

Código fuente: Lib/email/parser.py

Se pueden construir estructuras de objetos de mensaje de dos formas: pueden ser creados de puro invento al crear un objeto `EmailMessage`, añadir encabezados usando la interfaz de diccionario, y añadir carga(s) usando el método `set_content()` y otros relacionados, o pueden ser creados al analizar una representación serializada de un mensaje de correo electrónico.

El paquete `email` proporciona un analizador estándar que entiende la mayoría de estructuras de documentos de correo electrónico, incluyendo documentos MIME. Le puedes pasar al analizador bytes, una cadena de caracteres o una archivo de objeto, y el analizador te retornará la instancia `EmailMessage` raíz de la estructura del objeto. Para mensajes simples que no sean MIME, la carga de su objeto raíz probablemente será una cadena de caracteres conteniendo el texto o el mensaje. Para mensajes MIME, el objeto raíz retornará `True` de su método `is_multipart()`, y las subpartes pueden ser accedidas a través de los métodos de manipulación de carga, tales como `get_body()`, `iter_parts()`, y `walk()`.

De hecho hay dos interfaces de analizadores disponibles para usar, la API `Parser` y la API progresiva `FeedParser`. La API `Parser` es más útil si tú tienes el texto del mensaje entero en memoria, o si el mensaje entero reside en un archivo en el sistema. `FeedParser` es más apropiado cuando estás leyendo el mensaje de un stream que puede ser bloqueado esperando más entrada (tal como leer un mensaje de correo electrónico de un socket). El `FeedParser` puede consumir y analizar el mensaje de forma progresiva, y sólo retorna el objeto raíz cuando cierras el analizador.

Tenga en cuenta que el analizador puede ser extendido en formas limitadas, y por supuesto puedes implementar tu propio analizador completamente desde cero. Toda la lógica que conecta el analizador empaquetado del paquete `email` y la clase `EmailMessage` está encarnada en la clase `policy`, por lo que un analizador personalizado puede crear árboles de objetos mensaje en cualquier forma que encuentre necesario al implementar versiones personalizadas de los métodos apropiados de `policy`.

## API FeedParser

La clase `BytesFeedParser`, importado del módulo `email.feedparser`, proporciona una API que es propicia para el análisis progresivo de mensajes de correo electrónico, tal como sería necesario cuando se esté leyendo el texto de un mensaje de correo electrónico de una fuente que puede bloquear (tal como un socket). Desde luego se puede usar la clase `BytesFeedParser` para analizar un mensaje de correo electrónico completamente contenido en un bytes-like object, cadena de caracteres, o archivo, pero la API `BytesParser` puede ser más conveniente para tales casos de uso. Las semánticas y resultados de las dos API de los analizadores son idénticas.

La API de `BytesFeedParser` es simple; puedes crear una instancia, le proporcionas un montón de bytes hasta que no haya más necesidad de hacerlo, entonces cierras el analizador para recuperar el objeto del mensaje raíz. El `BytesFeedParser` es extremadamente preciso cuando está analizando mensajes conformes al estándar, y hace un buen trabajo al analizar mensajes no conformes, proporcionando información acerca de cómo un mensaje fue considerado inservible. Ingresará una lista de cualquier problema que encontró en el atributo `defects` del objeto mensaje. Véase el módulo `email.errors` para la lista de defectos que puede encontrar.

Aquí está el API para `BytesFeedParser`:

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

  Crea una instancia de `BytesFeedParser`. El argumento opcional _factory es un invocable sin argumentos; si no se especifica, usa el `message_factory` de policy. Llama a _factory cuando sea necesario un nuevo objeto mensaje.

  Si se especifica policy, usa las reglas que especifica para actualizar la representación del mensaje. Si policy no está puesta, usa la política (policy) `compat32`, que mantiene compatibilidad con la versión 3.2 de Python del paquete de correo electrónico y proporciona a `Message` como la fábrica por defecto. Todas las otras políticas proveen a `EmailMessage` como el _factory por defecto. Para más información en lo demás que policy controla, véase la documentación `policy`.

  Nota: La palabra clave *policy* siempre debe estar especificada; El valor por defecto cambiará a `email.policy.default` en una versión futura de Python.

  Nuevo en la versión 3.2.

  Distinto en la versión 3.3: Se añadió la palabra clave policy.

  Distinto en la versión 3.6: _factory es por defecto la policy `message_factory`.

  `feed`(data)

    Le proporciona al analizador algunos datos más. data debe ser un bytes-like object conteniendo una o más líneas. Las líneas pueden ser parciales y el analizador va a juntar tales líneas parciales apropiadamente. las líneas pueden tener cualquiera de las tres terminaciones de línea comunes: retorno de cargo (retorno de cargo), nueva línea (newline), o retorno de cargo y nueva línea (pueden ser mezclados).

  `close`()

    Completa el análisis de todos los datos previamente proporcionados y retorna la raíz del objeto mensaje. No está definido lo que pasa si se llama a `feed()` después de que este método haya sido llamado.

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

  Funciona como `BytesFeedParser` excepto que la entrada al método `feed()` no debe ser una cadena de caracteres. Esto es utilidad limitada, ya que la única manera de que tal mensaje sea válido es que sólo contenga texto ASCII o, si `utf8` es `True`, sin binarios adjuntos.

  Distinto en la versión 3.3: Se añadió la palabra clave policy.

## API Parser

La clase `BytesParser`, importado del módulo `email.parser`, proporciona una API que puede ser usada para analizar un mensaje cuando el contenido completo del mensaje esté disponible en un bytes-like object o archivo. El módulo `email.parser` también proporciona a `Parser` para analizar cadenas de caracteres, y analizadores de sólo cabeceras, `BytesHeaderParser` y `HeaderParser` que pueden ser usados si sólo estás interesado en las cabeceras del mensaje. `BytesHeaderParser` y `HeaderParser` puede ser más rápidos en estas situaciones, ya que no intentan analizar el cuerpo del mensaje, en vez de eso configuran la carga al cuerpo puro.

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

  Crea una instancia de `BytesParser`. Los argumentos _class y policy tiene el mismo significado y semántica que los argumentos _factory y policy de `BytesFeedParser`.

  Nota: La palabra clave *policy* siempre debe estar especificada; El valor por defecto cambiará a `email.policy.default` en una versión futura de Python.

  Distinto en la versión 3.3: Se eliminó el argumento strict que fue deprecado en 2.4. Se añadió la palabra clave policy.

  Distinto en la versión 3.6: _class es por defecto la política `message_factory`.

  `parse`(fp, headersonly=False)

    Lee todos los datos del objeto binario parecido a archivo fp, analiza los bytes resultantes, y retorna el objeto mensaje. fp debe soportar tanto el método `readline()` como el método `read()`.

    Los bytes contenidos en fp deben ser formateados como un bloque de cabeceras de estilo y líneas de continuación de cabecera de RFC 5322 (o, si `utf8` es `True`, RFC 6532). El bloque cabecera se termina o al final de los datos o por una línea blanca. Después del bloque de cabecera esta él cuerpo del mensaje (que puede contener subpartes codificadas como MIME, incluyendo subpartes con un Content-Transfer-Encoding de `8bit`).

    El argumento opcional headersonly es un flag que especifica si se debe analizar después de leer las cabeceras o no. El valor por defecto es `False`, significando que analiza el contenido entero del archivo.

  `parsebytes`(bytes, headersonly=False)

    Similar al método `parse()`, excepto que toma un bytes-like object en vez de un objeto similar a un archivo. Llamar a este método en un bytes-like object es equivalente a envolver a bytes en una instancia de `BytesIO` primero y llamar a `parse()`.

    El argumento opcional headersonly es como el método `parse()`.

  Nuevo en la versión 3.2.

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

  Exactamente como `BytesParser`, excepto que headersonly es por defecto `True`.

  Nuevo en la versión 3.3.

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

  Esta clase es paralela a `BytesParser`, pero trata entradas de cadenas de caracteres.

  Distinto en la versión 3.3: Se eliminó el argumento strict. Se añadió la palabra clave policy.

  Distinto en la versión 3.6: _class es por defecto la política `message_factory`.

  `parse`(fp, headersonly=False)

    Lee todos los datos del modo texto del objeto parecido a archivo fp, analiza el texto resultante, y retorna el objeto mensaje raíz. fp debe soportar tanto el método `readline()` y el método `read()` en objetos parecidos a archivos.

    Además de el requisito del modo texto, este método opera como `BytesParser.parse()`.

  `parsestr`(text, headersonly=False)

    Similar al método `parse()`, excepto que toma un objeto de cadena de caracteres de un objeto similar a un archivo. Llamar a este método en una cadena de caracteres es equivalente a envolver a text en una instancia de `StringIO` primero y llamar a `parse()`.

    El argumento opcional headersonly es como el método `parse()`.

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

  Exactamente como `Parser`, excepto que headersonly es por defecto `True`.

Ya que crear una estructura de un objeto mensaje de una cadena de caracteres o un objeto archivo es una tarea tan común, Se proporcionaron 4 funciones como una conveniencia. Están disponibles en paquete de espacio de nombres de alto nivel `email`.

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

  Retorna una estructura del objeto mensaje de un bytes-like object. Esto es equivalente a `BytesParser().parsebytes(s)`. El argumento opcional _class y policy son interpretados como sucede con el constructor de clase `BytesParser`.

  Nuevo en la versión 3.2.

  Distinto en la versión 3.3: Se eliminó el argumento strict. Se añadió la palabra clave policy.

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

  Retorna una estructura árbol del objeto mensaje de un file object binario abierto. Esto es equivalente a `BytesParser().parse(fp)`. _class y policy son interpretados como sucede con el constructor de clase `BytesParser`.

  Nuevo en la versión 3.2.

  Distinto en la versión 3.3: Se eliminó el argumento strict. Se añadió la palabra clave policy.

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

  Retorna una estructura del objeto mensaje de una cadena de caracteres. Esto es equivalente a `Parser().parsestr(s)`. _class y policy son interpretados como sucede con el constructor de clase `Parser`.

  Distinto en la versión 3.3: Se eliminó el argumento strict. Se añadió la palabra clave policy.

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

  Retorna una estructura árbol del objeto mensaje de un file object abierto. Esto es equivalente a `Parser().parse(fp)`. _class y policy son interpretados como sucede con el constructor de clase `Parser`.

  Distinto en la versión 3.3: Se eliminó el argumento strict. Se añadió la palabra clave policy.

  Distinto en la versión 3.6: _class es por defecto la política `message_factory`.

Aquí está un ejemplo de cómo puedes usar `message_from_bytes()` en una entrada interactiva de Python:

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

## Notas adicionales

Aquí están algunas notas sobre la semántica del análisis:

- La mayoría de los mensajes de tipo que no son multipart son actualizados como un solo objeto mensaje con una carga de cadena de caracteres. Estos objetos retornarán `False` para `is_multipart()`, y `iter_parts()` cederá (yield) una lista vacía.

- Todos los mensajes de tipo multipart serán analizados como un objeto mensaje contenedor con una lista de objetos sub-mensajes para sus cargas. El mensaje del contenedor externo retornará `True` para `is_multipart()`, y `iter_parts()` cederá (yield) una lista de subpartes.

- La mayoría de mensajes con una tipo de contenido de message/* (tal como message/delivery-status y message/rfc822) también serán analizados como objetos contenedores que contienen una lista de cargas de longitud 1. Su método `is_multipart()` retornará `True`. El único elemento cedido (yielded) por `iter_parts()` será un objeto sub-mensaje.

- Algunos mensajes de conformidad no estándar pueden no ser internamente consistentes acerca de su multipart-idad. Tales mensajes pueden tener una cabecera Content-Type de tipo multipart, pero su método `is_multipart()` puede retornar `False`. Si tales mensajes son analizados con `FeedParser`, tendrán una instancia de la clase `MultipartInvariantViolationDefect` en su lista de atributos defects. Véase `email.errors` para más detalles.