Вопрос по python, email, python-2.7, google-app-engine, email-attachments – Получение вложений электронной почты в ошибках App Engine Python в текстовом файле Unicode

1

У меня есть некоторый код для анализа электронной почты и поиска вложений, а затем сохранения их в хранилище данных как db.BlobProperties (может позже изменить это на Blobstore). Проблема в том, что когда я отправляю текстовый файл в кодировке UTF8, возникает ошибка.

Код в основном сохраняет файл и возвращает ключ, который преобразуется в строку и затем сохраняется в родительском объекте электронной почты. Как вы можете видеть, я декодирую файл, а затем сохраняю его как блоб. Я отправил много вложений, и этот код работает на всем, кроме текста, закодированного с помощью Unicode. Есть лучший способ сделать это? Что я могу сделать для обработки текстовых вложений Unicode?

фрагмент кода

    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()

Я пытался использоватьfile_blob = str(file_blob) в вышесказанном безрезультатно. Это просто нарушает код, и файл никогда не сохраняется.

журнал 1 текстового файла 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)

Журнал 2 удаления filecontents.decode () и замены его только на 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)
& quot; Возвращает ошибку & quot; монументально бесполезен. Какая ошибка? Опубликовать (завершить) трассировку стека! Nick Johnson
Добавлен след. Я думал, что было ясно, что он возвращает сообщение об ошибке значения из сообщения. Спасибо за помощь. Mark Finch

Ваш Ответ

2   ответа
1

Проверьте, помогает ли этот код:

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

   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)))
Можете ли вы объяснить, что вы сделали иначе, чем ОП?
1

Полезные нагрузки вложений являются экземплярамиEncodedPayload учебный класс. Вложения имеют кодировку и необязательный набор символов. Первый относится к кодировкам передачи, таким как base64; последнее относится к кодировкам символов, таким как UTF-8 (здесь набор символов немного устаревший и вводящий в заблуждение термин).EncodedPayload.decode() Этот метод декодирует как кодировку передачи, так и кодировку текста, что, как вы заметили, не очень полезно, если вы просто хотите получить исходные байты, прикрепленные пользователем к их сообщению.

Здесь можно использовать несколько подходов, но я рекомендую продублировать логику EncodedPayload для декодирования кодирования передачи, которая выглядит примерно так:

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

Обратите внимание, что если вложениеwas текст, вам нужно включить кодировку символов при сохранении, иначе не будет возможности интерпретировать его при отправке обратно пользователю - исходный текст мог быть закодирован с использованием любой кодировки символов.

Аналогичным образом, вы также должны сохранить mimetype вложения, если можете, но это, похоже, не отображается нигде в API. Возможно, вы захотите вообще отказаться от использования класса IncomingMessage и вместо этого декодировать тело запроса POST с помощью модуля сообщений Python mime.

Извините, я редактировал комментарий, когда вы ответили и удалили его, поскольку ваш комментарий поступил из-за правила 5 мин. Поправьте меня, если я ошибаюсь, но вложенные файлы приходят в кодировке Base64. Мы запускаем их декодирование, чтобы вернуть их в исходное состояние. По моему мнению, ожидаемое поведение состоит в том, что если я могу сохранить файл PDF, DOC, Jpeg и GIF с использованием этого метода, то он не должен обрабатывать файл TXT иначе. Перекодирование в этом случае не работает, так как будет выдано сообщение об ошибке, что он ожидал str и получил x. Я ищу обходной путь, чтобы разобраться с этим делом. Mark Finch
@MarkFinch Iffilecontents это строка, вызывающаяfilecontents.decode() декодирует его в строку Unicode, используя системный кодек по умолчанию. Если ваши данные в кодировке base64, вы должны использоватьbase64.b64decode(filecontents) или жеfilecontents.decode('base64'), Почтовые вложения могут быть закодированы несколькими способами, и способ их кодирования указан в полях заголовка вложения.
Как я только что сказал, звоню.decode() в строке base64 не декодирует ее (по умолчанию; доступно много кодеков), она декодирует ее в виде строки Unicode. Если вам нужно декодирование с помощью base64, вы вызываете неправильный метод.
@MarkFinch BlobProperty не может просто хранить байты, потому что нет единственной канонической кодировки для строки юникода. Для того, чтобы хранить строку в юникоде, вы должны сначала выбрать кодировку и кодировать ее таким образом самостоятельно. Что касается угадывания миметипов вложений, то это не то, что вам нужно делать, если бы не недостатки библиотеки входящей почты. Я предлагаю использовать API сообщений MIME Python и самостоятельно декодировать сообщение (отправленное как тело запроса POST), что позволит вам получить доступ ко всем полям заголовка.
Контент файла представляет собой текстовый документ, который на самом деле не является строкой, а представляет собой другой формат файла. В любом случае AppEngine рассматривает его как строку. Использование блока Try Except устраняет проблему повторной доставки сообщения (еще раз спасибо), но файл теряется, так как он генерирует ошибку об Unicode. Кто-то уже должен был обойти это. Если хранение файлов в буфере исправляет это, я рад этому ответу. Я собирался изменить его там в любом случае из-за шанса, что кто-то отправит вложение более 1 МБ. В любом случае, я хотел бы найти работу, так как это может произойти в будущем. Mark Finch

Похожие вопросы