# `email.message.Message`: Representar un mensaje de correo electrónico usando la API `compat32`

La clase `Message` es muy similar a la clase `EmailMessage`, sin los métodos añadidos por esa clase y con el comportamiento predeterminado de algunos otros métodos siendo ligeramente diferente. También documentamos aquí algunos métodos que, aun siendo soportados por `EmailMessage`, no están recomendados a no ser que estés lidiando con código heredado.

Por lo demás, la filosofía y estructura de las dos clases es la misma.

Este documento describe el comportamiento bajo la política por defecto (para `Message`) `Compat32`. Si vas a usar otra política, deberías estar usando la clase `EmailMessage` en su lugar.

Un mensaje de correo electrónico consta de headers y payload. Los encabezados deben ser nombres y valores de estilo RFC 5322, donde el nombre del campo y el valor están separados por dos puntos. Los dos puntos no forman parte del nombre del campo ni del valor del campo. La carga útil puede ser un mensaje de texto simple, un objeto binario o una secuencia estructurada de submensajes, cada uno con su propio conjunto de encabezados y su propia carga útil. El último tipo de carga útil se indica mediante el mensaje que tiene un tipo MIME como multipart/* o message/rfc822.

El modelo conceptual proporcionado por un objeto `Message` es el de un diccionario ordenado de encabezados con métodos adicionales para acceder a información especializada de los encabezados, para acceder a la carga, para generar una versión serializada del mensaje y para recorrer recursivamente el árbol del objeto. Ten en cuenta que son soportados encabezados duplicados pero deben ser usados métodos especiales para acceder a ellos.

El pseudodiccionario `Message` es indexado por los nombres de encabezados, los cuales deben ser valores ASCII. Los valores del diccionario son cadenas que se supone que contienen sólo caracteres ASCII; hay algún manejo especial para la entrada no ASCII, pero esta no siempre produce los resultados correctos. Los encabezados son almacenados y retornados preservando mayúsculas y minúsculas, pero los nombres de campos son emparejados sin distinción entre mayúsculas y minúsculas. También puede haber sólo un encabezado de envoltura, también conocido como el encabezado Unix-From o el encabezado `From_`. La carga (payload) es una cadena o bytes, en el caso de objetos de mensajes simples, o una lista de objetos `Message`, para contenedores de documentos MIME (ej. multipart/* y message/rfc822).

Aquí están los métodos de la clase `Message`:

class email.message.Message(policy=compat32)

  Si se especifica policy (debe ser una instancia de una clase `policy`) utiliza las reglas que especifica para actualizar y serializar la representación del mensaje. Si no se define policy, utiliza la política `compat32`, la cual mantiene compatibilidad con la versión de Python 3.2 del paquete email. Para más información consulta la documentación de `policy`.

  Distinto en la versión 3.3: El argumento de palabra clave policy fue añadido.

  as_string(unixfrom=False, maxheaderlen=0, policy=None)

    Retorna el mensaje completo aplanado como una cadena. Cuando el parámetro opcional unixfrom es verdadero, el encabezado de envoltura se incluye en la cadena retornada. unixfrom es por defecto `False`. Por razones de compatibilidad con versiones anteriores, maxheaderlen es `0` por defecto, por lo que si quieres un valor diferente debes debes sobreescribirlo explícitamente (el valor especificado por max_line_length en la política será ignorado por este método). El argumento policy puede ser usado para sobrescribir la política por defecto obtenida de la instancia del mensaje. Esto puede ser usado para controlar algo del formato producido por el método, ya que la policy especificada puede ser pasada al `Generator`.

    Aplanar el mensaje puede desencadenar cambios en `Message` si por defecto necesita ser rellenado para completar la transformación a una cadena (por ejemplo, límites MIME pueden ser generados o modificados).

    Note that this method is provided as a convenience and may not always format the message the way you want. For example, by default it does not do the mangling of lines that begin with `From` that is required by the Unix mbox format. For more flexibility, instantiate a `Generator` instance and use its `flatten()` method directly. For example:

        from io import StringIO
        from email.generator import Generator
        fp = StringIO()
        g = Generator(fp, mangle_from_=True, maxheaderlen=60)
        g.flatten(msg)
        text = fp.getvalue()

    Si el objeto de mensaje contiene datos binarios que no están codificados de acuerdo a los estándares RFC, los datos no compatibles serán reemplazados por puntos de código Unicode de «carácter desconocido». (Consulta también `as_bytes()` y `BytesGenerator`.)

    Distinto en la versión 3.4: el argumento de palabra clave policy fue añadido.

  __str__()

    Equivalente a `as_string()`. Permite a `str(msg)` producir una cadena conteniendo el mensaje formateado.

  as_bytes(unixfrom=False, policy=None)

    Retorna el mensaje completo aplanado como un objeto de bytes. Cuando el argumento opcional unixfrom es verdadero, el encabezado de envoltura se incluye en la cadena retornada. unixfrom es por defecto `False`. El argumento policy puede ser usado para sobrescribir la política por defecto obtenida desde la instancia del mensaje. Esto puede ser usado para controlar algo del formato producido por el método, ya que el policy especificado será pasado al `BytesGenerator`.

    Aplanar el mensaje puede desencadenar cambios en `Message` si por defecto necesita ser rellenado para completar la transformación a una cadena (por ejemplo, límites MIME pueden ser generados o modificados).

    Note that this method is provided as a convenience and may not always format the message the way you want. For example, by default it does not do the mangling of lines that begin with `From` that is required by the Unix mbox format. For more flexibility, instantiate a `BytesGenerator` instance and use its `flatten()` method directly. For example:

        from io import BytesIO
        from email.generator import BytesGenerator
        fp = BytesIO()
        g = BytesGenerator(fp, mangle_from_=True, maxheaderlen=60)
        g.flatten(msg)
        text = fp.getvalue()

    Nuevo en la versión 3.4.

  __bytes__()

    Equivalente a `as_bytes()`. Permite a `bytes(msg)` producir un objeto de bytes conteniendo el mensaje formateado.

    Nuevo en la versión 3.4.

  is_multipart()

    Retorna `True` si la carga del mensaje es una lista de objetos heredados de `Message`, si no retorna `False`. Cuando `is_multipart()` retorna `False`, la carga debe ser un objeto de cadena (el cual puede ser una carga CTE codificada en binario). (Ten en cuenta que `is_multipart()` retornando `True` no significa necesariamente que «msg.get_content_maintype() == “multipart”» retornará `True`. Por ejemplo, `is_multipart` retornará `True` cuando el `Message` es de tipo `message/rfc822`.)

  set_unixfrom(unixfrom)

    Establece el mensaje del encabezado de envoltura a unixfrom, el cual debe ser una cadena.

  get_unixfrom()

    Retorna el mensaje del encabezado de envoltura. Por defecto a `None` si el encabezado de envoltura nunca fue definido.

  attach(payload)

    Añade el payload dado a la carga actual, la cual debe ser `None` o una lista de objetos `Message` antes de la invocación. Después de la invocación, la carga siempre será una lista de objetos `Message`. Si quieres definir la carga a un objeto escalar (ej. una cadena), usa `set_payload()` en su lugar.

    Este es un método heredado. En la clase `EmailMessage` su funcionalidad es remplazada por `set_content()` y los métodos relacionados `make` y `add`.

  get_payload(i=None, decode=False)

    Retorna la carga (payload) actual, la cual será una lista de objetos `Message` cuando `is_multipart()` es `True`, o una cadena cuando `is_multipart()` es `False`. Si la carga es una lista y mutas el objeto de lista, modificarás la carga del mensaje.

    Con el argumento opcional i, `get_payload()` retornará el elemento número i de la carga (payload), contando desde cero, si `is_multipart()` es `True`. Un `IndexError` será generado si i es menor que 0 ó mayor o igual que el número de elementos en la carga. Si la carga es una cadena (ej. `is_multipart()` es `False`) y se define i, se genera un `TypeError`.

    El argumento opcional decode es un indicador que determina si una carga debería ser decodificada o no, de acuerdo al encabezado Content-Transfer-Encoding. Cuando es `True` y el mensaje no es multiparte, la carga será decodificada si el valor de su encabezado es `quoted-printable` o `base64`. Si se usa alguna otra codificación o falta el encabezado Content-Transfer-Encoding, la carga es retornada tal cual (sin decodificar). En todos los casos el valor retornado son datos binarios. Si el mensaje es multiparte y el indicador decode es `True`, entonces se retorna `None`. Si la carga es base64 y no fue perfectamente formada (falta relleno, tiene caracteres fuera del alfabeto base64), entonces un defecto apropiado será añadido a la propiedad defect del mensaje (`InvalidBase64PaddingDefect` o `InvalidBase64CharactersDefect`, respectivamente).

    Cuando decode es `False` (por defecto) el cuerpo es retornado como una cadena sin decodificar el Content-Transfer-Encoding. Sin embargo, para un Content-Transfer-Encoding de 8bit, se realiza un intento para decodificar los bytes originales usando el `charset` especificado por el encabezado Content-Type, usando el manejador de error `replace`. Si ningún `charset` es especificado o si el `charset` dado no es reconocido por el paquete email, el cuerpo es decodificado usando el conjunto de caracteres ASCII por defecto.

    Este es un método heredado. En la clase `EmailMessage` su funcionalidad es remplazada por `get_content()` y `iter_parts()`.

  set_payload(payload, charset=None)

    Define la carga completa del objeto mensaje a payload. Es responsabilidad del cliente asegurar invariantes de carga. El argumento opcional charset define el conjunto de caracteres por defecto del mensaje; consulta `set_charset()` para más detalles.

    Este es un método heredado. En la clase `EmailMessage` su funcionalidad es remplazada por `set_content()`.

  set_charset(charset)

    Define el junto de caracteres de la carga a charset, el cual puede ser tanto una instancia `Charset` (ver `email.charset`), una cadena denominando un conjunto de caracteres, o `None`. Si es una cadena, será convertida a una instancia `Charset`. Si charset es `None`, el parámetro `charset` será eliminado del encabezado Content-Type (el mensaje no será modificado de otra manera). Cualquier otro valor lanzará un `TypeError`.

    Si no hay un encabezado existente MIME-Version, será añadido uno. Si no hay un encabezado existente Content-Type, será añadido uno con valor text/plain. Tanto como si el encabezado Content-Type existe actualmente como si no, su parámetro `charset` será establecido a charset.output_charset. Si charset.input_charset y charset.output_charset difieren, la carga será recodificada al output_charset. Si no hay un encabezado existente Content-Transfer-Encoding, entonces la carga será codificada por transferencia, si es necesario, usando el `Charset` especificado y un encabezado con el valor apropiado será añadido. Si ya existe un encabezado Content-Transfer-Encoding, la carga se asume que ya está correctamente codificada usando ese Content-Transfer-Encoding y no es modificada.

    Este es un método heredado. En la clase `EmailMessage` su funcionalidad es remplazada por el parámetro charset del método `email.emailmessage.EmailMessage.set_content()`.

  get_charset()

    Retorna la instancia `Charset` asociada con la carga del mensaje.

    Este es un método heredado. En la clase `EmailMessage` siempre retorna `None`.

  Los siguientes métodos implementan una interfaz parecida a un mapeo para acceder a los encabezados RFC 2822 del mensaje. Ten en cuenta que hay algunas diferencias semánticas entre esos métodos y una interfaz de mapeo normal (ej. diccionario). Por ejemplo, en un diccionario no hay claves duplicadas, pero aquí pueden haber encabezados de mensaje duplicados. También, en diccionarios no hay un orden garantizado de las claves retornadas por `keys()`, pero en un objeto `Message`, los encabezados siempre son retornados en el orden que aparecieron en el mensaje original, o en el que fueron añadidos al mensaje más tarde. Cualquier encabezado eliminado y vuelto a adicionar siempre es añadido al final de la lista de encabezados.

  Esas diferencias semánticas son intencionales y están sesgadas hacia la máxima comodidad.

  Ten en cuenta que en todos los casos, cualquier encabezado de envoltura presente en el mensaje no está incluido en la interfaz de mapeo.

  In a model generated from bytes, any header values that (in contravention of the RFCs) contain non-ASCII bytes will, when retrieved through this interface, be represented as `Header` objects with a charset of `unknown-8bit`.

  __len__()

    Retorna el número total de encabezados, incluyendo duplicados.

  __contains__(name)

    Retorna `True` si el objeto mensaje tiene un campo llamado name. La concordancia se realiza sin distinguir mayúsculas de minúsculas y name no debería incluir el caracter de doble punto final. Usado para el operador `in`, ej:

        if 'message-id' in myMessage:
           print('Message-ID:', myMessage['message-id'])

  __getitem__(name)

    Retorna el valor del campo del encabezado nombrado. name no debe incluir el separador de campo de doble punto. Si falta un encabezado, se retorna `None`; nunca se genera un error `KeyError`.

    Ten en cuenta que si el campo nombrado aparece más de una vez en los encabezados del mensaje, no se define cuales serán exactamente aquellos valores de campos retornados. Usa el método `get_all()` para obtener los valores de todos los encabezados nombrados existentes.

  __setitem__(name, val)

    Añade un encabezado al mensaje con el nombre de campo name y el valor val. El campo es añadido al final de los campos existentes del mensaje.

    Ten en cuenta que esto no sobreescribe ni elimina ningún encabezado existente con el mismo nombre. Si quieres asegurar que el nuevo encabezado es el único presente en el mensaje con el nombre de campo name, elimina el campo primero, ej:

        del msg['subject']
        msg['subject'] = 'Python roolz!'

  __delitem__(name)

    Elimina todas las ocurrencias de un campo con el nombre name de los encabezados del mensaje. No se genera ninguna excepción si el encabezado nombrado no está presente en los encabezados.

  keys()

    Retorna una lista de todos los nombres de campos de encabezados del mensaje.

  values()

    Retorna una lista de todos los valores de campos del mensaje.

  items()

    Retorna una lista de tuplas de dos elementos conteniendo todos los campos y valores de encabezados del mensaje.

  get(name, failobj=None)

    Return the value of the named header field. This is identical to `__getitem__()` except that optional failobj is returned if the named header is missing (defaults to `None`).

  Aquí hay algunos métodos útiles adicionales:

  get_all(name, failobj=None)

    Retorna una lista de todos los valores para el campo denominado name. Si no hay tales encabezados nombrados en el mensaje, retorna failobj (por defecto `None`).

  add_header(_name, _value, **_params)

    Configuración de encabezado extendida. Este método es similar a `__setitem__()` excepto que pueden ser provistos parámetros adicionales de encabezado como argumentos de palabra clave. _name es el campo de encabezado a añadir y _value es el valor primario para el encabezado.

    Para cada elemento en el diccionario de argumentos de palabra clave _params, la clave se toma como el nombre del parámetro con guiones bajos convertidos a guiones medios (ya que los guiones medios son ilegales como identificadores en Python). Normalmente, el parámetro será añadido como `key="value"` a no ser que el valor sea `None`, en cuyo caso sólo la clave será añadida. Si el valor contiene caracteres no ASCII, puede ser especificado como una tupla de tres elementos en el formato `(CHARSET, LANGUAGE, VALUE)`, donde `CHARSET` es una cadena que nombra el conjunto de caracteres a ser usado al codificar el valor, `LANGUAGE` puede normalmente ser definido a `None` o una cadena vacía (ver RFC 2231 para otras posibilidades) y `VALUE` es la cadena del valor conteniendo puntos de caracteres no ASCII. Si no se pasa una tupla de tres elementos y el valor contiene caracteres no ASCII, se codifica automáticamente en formato RFC 2231 usando `CHARSET` como `utf-8` y `LANGUAGE` como `None`.

    Aquí hay un ejemplo:

        msg.add_header('Content-Disposition', 'attachment', filename='bud.gif')

    Esto añadirá un encabezado que se verá como

        Content-Disposition: attachment; filename="bud.gif"

    Un ejemplo con caracteres no ASCII:

        msg.add_header('Content-Disposition', 'attachment',
                       filename=('iso-8859-1', '', 'Fußballer.ppt'))

    Lo que produce

        Content-Disposition: attachment; filename*="iso-8859-1''Fu%DFballer.ppt"

  replace_header(_name, _value)

    Reemplaza un encabezado. Reemplaza el primer encabezado encontrado en el mensaje que concuerda con _name, conservando el orden del encabezado y el nombre del campo. Si no se encuentra ningún encabezado que concuerde, se genera un error `KeyError`.

  get_content_type()

    Retorna el tipo de contenido del mensaje. La cadena retornada se fuerza a letras minúsculas de la forma maintype/subtype. Si no hay ningún encabezado Content-Type en el mensaje será retornado el tipo por defecto como es dado por `get_default_type()`. Dado que según RFC 2045, los mensajes tienen siempre un tipo predeterminado, `get_content_type()` siempre retornará un valor.

    RFC 2045 define el tipo predeterminado del mensaje a text/plain a no ser que aparezca dentro de un contenedor multipart/digest, en cuyo caso sería message/rfc822. Si el encabezado Content-Type tiene una especificación de tipo inválido, RFC 2045 ordena que el tipo por defecto sea text/plain.

  get_content_maintype()

    Retorna el tipo de contenido principal del mensaje. Esta es la parte maintype de la cadena retornada por `get_content_type()`.

  get_content_subtype()

    Retorna el tipo del subcontenido del mensaje. Esta es la parte subtype de la cadena retornada por `get_content_type()`.

  get_default_type()

    Retorna el tipo del contenido por defecto. La mayoría de mensajes tienen un tipo de contenido por defecto de text/plain, excepto para mensajes que son subpartes de contenedores multipart/digest. Tales subpartes tienen como tipo de contenido predeterminado message/rfc822.

  set_default_type(ctype)

    Establece el tipo de contenido por defecto. ctype debería ser text/plain o message/rfc822, aunque esto no es obligatorio. El tipo de contenido predeterminado no se almacena en el encabezado Content-Type.

  get_params(failobj=None, header='content-type', unquote=True)

    Retorna los parámetros del Content-Type del mensaje como una lista. Los elementos de la lista retornada son tuplas de dos elementos de pares clave/valor, tal y como son partidas por el signo `'='`. El lado izquierdo del `'='` es la clave, mientras el lado derecho es el valor. Si no hay signo `'='` en el parámetro, el valor es la cadena vacía, en caso contrario el valor es como se describe en `get_param()` y no está citado si el parámetro opcional unquote es `True` (por defecto).

    El parámetro opcional failobj es el objeto a retornar si no hay encabezado Content-Type. El parámetro opcional header es el encabezado a buscar en lugar de Content-Type.

    Este es un método heredado. En la clase `EmailMessage` su funcionalidad es remplazada por la propiedad params de los objetos individuales de encabezado retornados por los métodos de acceso del encabezado.

  get_param(param, failobj=None, header='content-type', unquote=True)

    Retorna el valor del parámetro param del encabezado Content-Type como una cadena. Si el mensaje no tiene encabezado Content-Type o si no existe tal parámetro, entonces se retorna failobj (por defecto es `None`).

    El parámetro opcional header, si es definido, especifica el encabezado del mensaje a usar en lugar de Content-Type.

    Las claves de parámetros siempre son comparadas distinguiendo entre mayúsculas y minúsculas. El valor de retorno puede ser una cadena, una tupla de 3 elementos si el parámetro fue codificado según RFC 2231. Cuando es una tupla de 3 elementos, los elementos del valor tienen la forma `(CHARSET, LANGUAGE, VALUE)`. Ten en cuenta que `CHARSET` y `LANGUAGE` pueden ser `None`, en cuyo caso debes considerar `VALUE` como codificado en el conjunto de caracteres `us-ascii`. Generalmente puedes ignorar `LANGUAGE`.

    Si a tu aplicación no le importa si el parámetro fue codificado según RFC 2231, puedes contraer el valor del parámetro invocando `email.utils.collapse_rfc2231_value()`, pasando el valor de retorno desde `get_param()`. Esto retornará una cadena Unicode convenientemente decodificada cuando el valor es una tupla o la cadena original sin entrecomillar si no lo es. Por ejemplo:

        rawparam = msg.get_param('foo')
        param = email.utils.collapse_rfc2231_value(rawparam)

    En cualquier caso, el valor del parámetro (tanto la cadena retornada o el elemento `VALUE` en la tupla de 3 elementos) siempre está sin entrecomillar, a no ser que unquote está establecido a `False`.

    Este es un método heredado. En la clase `EmailMessage` su funcionalidad es remplazada por la propiedad params de los objetos individuales de encabezado retornados por los métodos de acceso del encabezado.

  set_param(param, value, header='Content-Type', requote=True, charset=None, language='', replace=False)

    Establece un parámetro en el encabezado Content-Type. Si el parámetro ya existe en el encabezado, su valor será remplazado con value. Si el encabezado Content-Type no ha sido definido todavía para este mensaje, será establecido a text/plain y el nuevo valor del parámetro será añadido según RFC 2045.

    El parámetro opcional header especifica una alternativa a Content-Type y todos los parámetros serán entrecomillados si es necesario a no ser que el parámetro opcional requote sea `False` (por defecto es `True`).

    Si se especifica el parámetro opcional charset, el parámetro será codificado de acuerdo a RFC 2231. El parámetro opcional language especifica el lenguaje RFC 2231, por defecto una cadena vacía. Tanto charset como language deberían ser cadenas.

    Si replace es `False` (por defecto) el encabezado será movido al final de la lista de encabezados. Si replace es `True`, el encabezado será actualizado.

    Distinto en la versión 3.4: el parámetro de palabra clave `replace` fue añadido.

  del_param(param, header='content-type', requote=True)

    Elimina el parámetro dado completamente del encabezado Content-Type. El encabezado será reescrito en sí mismo sin el parámetro o su valor. Todos los valores serán entrecomillados si es necesario a no ser que requote sea `False` (por defecto es `True`). El parámetro opcional header especifica una alternativa a Content-Type.

  set_type(type, header='Content-Type', requote=True)

    Establece el tipo y subtipo principal para el encabezado Content-Type. type debe ser una cadena de la forma maintype/subtype, si no será generado un `ValueError`.

    Este método remplaza el encabezado Content-Type, manteniendo todos los parámetros en su lugar. Si requote es `False`, este dejará el encabezado existente tal como está, en caso contrario los parámetros serán entrecomillados (por defecto).

    Un encabezado alternativo puede ser especificado en el argumento header. Cuando el encabezado Content-Type es definido, un encabezado MIME-Version también es añadido.

    Este es un método heredado. En la clase `EmailMessage` su funcionalidad es remplazada por los métodos `make_` y `add_`.

  get_filename(failobj=None)

    Retorna el valor del parámetro `filename` del encabezado Content-Disposition del mensaje. Si el encabezado no tiene un parámetro `filename`, este método recurre a buscar el parámetro `name` en el encabezado Content-Type. Si tampoco se encuentra o falta el encabezado, entonces retorna failobj. La cadena retornada siempre será sin entrecomillar según `email.utils.unquote()`.

  get_boundary(failobj=None)

    Retorna el valor del parámetro `boundary` del encabezado Content-Type del mensaje o failobj tanto si falta el encabezado como si no tiene parámetro `boundary`. La cadena retornada siempre será sin entrecomillar según `email.utils.unquote()`.

  set_boundary(boundary)

    Establece el parámetro `boundary` del encabezado Content-Type a boundary. `set_boundary()` siempre entrecomillará boundary si es necesario. Se genera `HeaderParseError` si el objeto de mensaje no tiene encabezado Content-Type.

    Ten en cuenta que usar este método es sutilmente diferente a borrar el antiguo encabezado Content-Type y añadir uno nuevo con el nuevo límite mediante `add_header()` porque `set_boundary()` preserva el orden del encabezado Content-Type en la lista de encabezados. Sin embargo, no conserva ninguna línea de continuación que pueden haber estado presentes en el encabezado original Content-Type.

  get_content_charset(failobj=None)

    Retorna el parámetro `charset` del encabezado Content-Type, forzado a letras minúsculas. Si no hay un encabezado Content-Type o si ese encabezado no tiene parámetro `charset`, se retorna failobj.

    Ten en cuenta que este método difiere de `get_charset()`, el cual retorna la instancia `Charset` para la codificación por defecto del cuerpo del mensaje.

  get_charsets(failobj=None)

    Retorna una lista conteniendo los nombres de los conjuntos de caracteres en el mensaje. Si el mensaje es multipart, entonces la lista contendrá un elemento para cada subparte en la carga (payload), en caso contrario será una lista de un elemento.

    Cada elemento en la lista será una cadena la cual es el valor del parámetro `charset` en el encabezado Content-Type para la subparte representada. Sin embargo, si la subparte no tiene encabezado Content-Type, no tiene parámetro `charset` o no es del tipo MIME text principal, entonces ese elemento en la lista retornada será failobj.

  get_content_disposition()

    Retorna el valor en minúsculas (sin parámetros) del encabezado del mensaje Content-Disposition si tiene uno o `None`. Los valores posibles para este método son inline, attachment o `None` si el mensaje sigue el RFC 2183.

    Nuevo en la versión 3.5.

  walk()

    El método `walk()` es un generador de todo propósito el cual puede ser usado para iterar sobre todas las partes y subpartes de árbol de objeto de mensaje, en orden de recorrido de profundidad primero. Siempre usarás típicamente `walk()` como iterador en un bucle `for`; cada iteración retorna la siguiente subparte.

    Aquí hay un ejemplo que imprime el tipo MIME de cada parte de una estructura de mensaje multiparte:

        >>> for part in msg.walk():
        ...     print(part.get_content_type())
        multipart/report
        text/plain
        message/delivery-status
        text/plain
        text/plain
        message/rfc822
        text/plain

    `walk` itera sobre las subpartes de cualquier parte donde `is_multipart()` retorna `True`, aunque `msg.get_content_maintype() == 'multipart'` puede retornar `False`. Vemos esto en nuestro ejemplo haciendo uso de la función de ayuda de depuración `_structure`:

        >>> for part in msg.walk():
        ...     print(part.get_content_maintype() == 'multipart',
        ...           part.is_multipart())
        True True
        False False
        False True
        False False
        False False
        False True
        False False
        >>> _structure(msg)
        multipart/report
            text/plain
            message/delivery-status
                text/plain
                text/plain
            message/rfc822
                text/plain

    Aquí las partes de `message` no son `multiparts`, pero contienen subpartes. `is_multipart()` retorna `True` y `walk` desciende a las subpartes.

  Los objetos `Message` pueden contener opcionalmente dos atributos de instancia, los cuales pueden ser usados al generar el texto plano de un mensaje MIME.

  preamble

    El formato de un documento MIME permite algo de texto entre la línea en blanco que sigue a los encabezados y la primera cadena límite multiparte. Normalmente, este texto nunca es visible en un lector de correo compatible con MIME porque queda fuera de la armadura MIME estándar. Sin embargo, viendo el texto del mensaje en crudo o viendo el mensaje en un lector no compatible con MIME, este texto puede volverse visible.

    El atributo preamble contiene este texto de refuerzo adicional para documentos MIME. Cuando el `Parser` descubre algo de texto después de los encabezados pero antes de la primera cadena límite, asigna este texto al atributo preamble del mensaje. Cuando el `Generator` está escribiendo la representación de texto sin formato de un mensaje MIME y puede encontrar el mensaje como un atributo preamble, escribirá este texto en el área entre los encabezados y el primer límite. Consulta `email.parser` y `email.generator` para más detalles.

    Ten en cuenta que si el objeto de mensaje no tiene preámbulo, el atributo preamble será `None`.

  epilogue

    El atributo epilogue actúa de la misma manera que el atributo preamble, excepto que contiene texto que aparece entre el último límite y el fin del mensaje.

    No necesitas establecer el epílogo de la cadena vacía en orden para el `Generator` para imprimir una nueva línea al final del archivo.

  defects

    El atributo defects contiene una lista de todos los problemas encontrados al analizar este mensaje. Consulta `email.errors` para una descripción detallada de los posibles defectos de análisis.