www org for python email character-encoding python-3.x mime

org - ¿Cómo uso el módulo de correo electrónico Python 3.2 para enviar mensajes Unicode codificados en utf-8 con imprimible entre comillas?



python 64 bits for windows (2)

Deseo enviar mensajes de correo electrónico que tengan cuerpos Unicode arbitrarios en un programa Python 3.2. Pero, en realidad, estos mensajes consistirán en gran parte de texto ASCII de 7 bits. Entonces me gustaría que los mensajes codificados en utf-8 usen citado-imprimible. Hasta ahora, he encontrado que esto funciona, pero parece incorrecto:

c = email.charset.Charset(''utf-8'') c.body_encoding = email.charset.QP m = email.message.Message() m.set_payload("My message with an ''/u05d0'' in it.".encode(''utf-8'').decode(''iso8859-1''), c)

Esto da como resultado un mensaje de correo electrónico con exactamente el contenido correcto:

To: [email protected] From: [email protected] Subject: This is a subjective subject. MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable My message with an ''=D7=90'' in it.

En particular, b''/xd7/x90''.decode(''utf-8'') da como resultado el carácter Unicode original. Entonces, la codificación quoted-printable está representando correctamente el utf-8 . Soy muy consciente de que este es un hack increíblemente feo. Pero funciona.

Esto es Python 3. Se espera que las cadenas de texto siempre sean unicode. No debería tener que decodificarlo para utf-8. Y luego convertirlo de bytes a str por .decode(''iso8859-1'') es un hack horrible, y tampoco debería tener que hacer eso.

Es el módulo de email simplemente roto con respecto a las codificaciones? ¿No estoy recibiendo algo?

Intenté simplemente configurarlo, sin ningún juego de caracteres. Eso me deja con un mensaje de correo electrónico Unicode, y eso no está bien. También intenté dejar de encode y decode pasos. Si los dejo a los dos, se queja de que el /u05d0 está fuera de rango al tratar de decidir si ese carácter necesita ser citado en la codificación imprimible entre comillas. Si lo dejo en solo el paso de encode , se queja amargamente de cómo estoy pasando bytes y quiere un str .


Corriendo

import email import email.charset import email.message c = email.charset.Charset(''utf-8'') c.body_encoding = email.charset.QP m = email.message.Message() m.set_payload("My message with an ''/u05d0'' in it.", c) print(m.as_string())

Otorga este mensaje de seguimiento:

File "/usr/lib/python3.2/email/quoprimime.py", line 81, in body_check return chr(octet) != _QUOPRI_BODY_MAP[octet] KeyError: 1488

Ya que

In [11]: int(''5d0'',16) Out[11]: 1488

está claro que el unicode ''/u05d0'' es el personaje problemático. _QUOPRI_BODY_MAP se define en quoprimime.py por

_QUOPRI_HEADER_MAP = dict((c, ''=%02X'' % c) for c in range(256)) _QUOPRI_BODY_MAP = _QUOPRI_HEADER_MAP.copy()

Este dict solo contiene claves del range(256) . Entonces creo que tienes razón; quoprimime.py no se puede utilizar para codificar unicode arbitrario.

Como solución alternativa, puede usar (por defecto) base64 omitiendo

c.body_encoding = email.charset.QP

Tenga en cuenta que la última versión de quoprimime.py no utiliza _QUOPRI_BODY_MAP en absoluto, por lo que usar el último Python podría solucionar el problema.


Ese paquete de correo electrónico no se confunde sobre cuál es cuál (datos binarios codificados en modo Unicode frente a transferencia de contenido), pero la documentación no lo deja muy claro, ya que gran parte de la documentación data de una época en la que "codificación" significaba contenido codificación de transferencia. Estamos trabajando en una mejor API que hará todo esto más fácil de asimilar (y mejores documentos).

De hecho, hay una manera de hacer que el paquete de correo electrónico use QP para cuerpos utf-8, pero no está muy bien documentado. Lo haces así:

>>> charset.add_charset(''utf-8'', charset.QP, charset.QP) >>> m = MIMEText("This is utf-8 text: á", _charset=''utf-8'') >>> str(m) ''Content-Type: text/plain; charset="utf-8"/nMIME-Version: 1.0/nContent-Transfer-Encoding: quoted-printable/n/nThis is utf-8 text: =E1''