Recepción de archivos adjuntos de correo electrónico en errores de App Engine Python en un archivo de texto Unicode

Tengo algo de código para analizar un correo electrónico y encontrar los archivos adjuntos y luego almacenarlos en el almacén de datos como db.BlobProperties (podría cambiar eso a Blobstore más adelante) El problema es que cuando envío un archivo de texto codificado en UTF8, genera un error.

El código básicamente guarda el archivo y devuelve una clave que se convierte en una cadena que luego se almacena en la entidad de correo electrónico principal. Como puede ver, descifro el archivo y luego lo guardo como un blob. He enviado muchos archivos adjuntos y este código funciona en todo menos en texto codificado con Unicode. ¿Hay una mejor manera de hacer esto? ¿Qué puedo hacer para manejar los archivos adjuntos de texto Unicode?

código snipit

my_file = [] my_list = [] if hasattr(mail_message, 'attachments'): file_name = "" file_blob = "" for filename, filecontents in mail_message.attachments: file_name = filename file_blob = filecontents.decode() my_file.append(file_name) my_list.append(str(store_file(self, file_name, file_blob))) 

store_file

 def store_file(self, file_name, file_blob): new_file = myblob(file_name = file_name, file_blob = file_blob) return new_file.put() 

He intentado usar file_blob = str(file_blob) en el anterior sin éxito. Eso solo rompe el código y el archivo nunca se almacena.

log 1 del archivo de texto Unicode

 Property file_blob must be convertible to a Blob instance (Blob() argument should be str instance, not unicode) Traceback (most recent call last): File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/webapp2.py", line 1530, in __call__ rv = self.router.dispatch(request, response) File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/webapp2.py", line 1278, in default_dispatcher return route.handler_adapter(request, response) File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/webapp2.py", line 1102, in __call__ return handler.dispatch() File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/webapp2.py", line 572, in dispatch return self.handle_exception(e, self.app.debug) File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/webapp2.py", line 570, in dispatch return method(*args, **kwargs) File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/webapp/mail_handlers.py", line 65, in post self.receive(mail.InboundEmailMessage(self.request.body)) File "/base/data/home/apps/s~ae-baseapp/1.359073377819595139/controllers/InboundHandler.py", line 51, in receive file_list.append(str(store_file(self, file_name, file_blob))) File "/base/data/home/apps/s~ae-baseapp/1.359073377819595139/models/MyModel.py", line 63, in store_file file_blob = file_blob) File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/db/__init__.py", line 974, in __init__ prop.__set__(self, value) File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/db/__init__.py", line 614, in __set__ value = self.validate(value) File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/db/__init__.py", line 2780, in validate (self.name, self.data_type.__name__, err)) BadValueError: Property file_blob must be convertible to a Blob instance (Blob() argument should be str instance, not unicode) 

Registre 2 de eliminar filecontents.decode () y reemplazarlo con solo filecontents.

 Property file_blob must be convertible to a Blob instance (Blob() argument should be str instance, not EncodedPayload) Traceback (most recent call last): File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/webapp2.py", line 1530, in __call__ rv = self.router.dispatch(request, response) File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/webapp2.py", line 1278, in default_dispatcher return route.handler_adapter(request, response) File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/webapp2.py", line 1102, in __call__ return handler.dispatch() File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/webapp2.py", line 572, in dispatch return self.handle_exception(e, self.app.debug) File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.5.1/webapp2.py", line 570, in dispatch return method(*args, **kwargs) File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/webapp/mail_handlers.py", line 65, in post self.receive(mail.InboundEmailMessage(self.request.body)) File "/base/data/home/apps/s~ae-baseapp/1.359097282640216691/controllers/InboundHandler.py", line 57, in receive file_list.append(str(store_file(self, file_name, file_blob))) File "/base/data/home/apps/s~ae-baseapp/1.359097282640216691/models/MyModel.py", line 64, in store_file file_blob = file_blob) File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/db/__init__.py", line 974, in __init__ prop.__set__(self, value) File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/db/__init__.py", line 614, in __set__ value = self.validate(value) File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/db/__init__.py", line 2780, in validate (self.name, self.data_type.__name__, err)) BadValueError: Property file_blob must be convertible to a Blob instance (Blob() argument should be str instance, not EncodedPayload) 

Las cargas útiles de archivos adjuntos son instancias de la clase EncodedPayload . Los archivos adjuntos tienen una encoding y un conjunto de caracteres opcional. El primero se refiere a codificaciones de transferencia tales como base64; las últimas codificaciones de caracteres como UTF-8 (el conjunto de caracteres es un término un tanto anticuado y engañoso). El método EncodedPayload.decode() decodifica tanto la encoding de transferencia como la encoding de texto, lo que, como ha notado, no es muy útil si solo desea obtener los bytes originales que el usuario adjuntó a su mensaje.

Hay una serie de enfoques que puede tomar aquí, pero lo que recomendaría es duplicar la lógica de EncodedPayload para descodificar la encoding de transferencia, que se parece a esto:

 if filecontents.encoding and filecontents.encoding.lower() != '7bit': try: payload = filecontents.payload.decode(filecontents.encoding) except LookupError: raise UnknownEncodingError('Unknown decoding %s.' % filecontents.encoding) except (Exception, Error), e: raise PayloadEncodingError('Could not decode payload: %s' % e) else: payload = filecontents.payload 

Tenga en cuenta que si el archivo adjunto era texto, debe incluir la encoding de caracteres cuando lo almacene, o no habrá forma de interpretarlo cuando se lo envíe al usuario; el texto original podría haber sido codificado utilizando cualquier encoding de caracteres. .

Del mismo modo, también debe guardar el tipo MIME del archivo adjunto si puede, pero esto no parece estar expuesto en ninguna parte de la API. Es posible que desee considerar evitar el uso de la clase IncomingMessage y, en su lugar, descodificar el cuerpo de la solicitud POST utilizando el módulo de mensajes mime de Python.

Compruebe si este código ayuda:

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

  my_file = [] my_list = [] if hasattr(mail_message, 'attachments'): file_name = "" for filename, filecontents in mail_message.attachments: file_name = filename file_blob = filecontents.payload file_blob = file_blob.decode(filecontents.encoding) my_file.append(file_name) my_list.append(str(store_file(self, file_name, file_blob)))