5

I am working on an app to process emails hitting my mailbox. I have modified my mail settings to forward incoming mails to myapp. The mails reaching myapp will be routed to the handler script ("handle_incoming_email.py") where it will be processed. My app.yaml file looks like this

app.yaml

application: myapp
version: 1-1
runtime: python27
api_version: 1
threadsafe: false
default_expiration: "360d"

handlers:
- url: /_ah/mail/.+
  script: myapp/utils/handle_incoming_email.py

The mail handler script is given below

handle_incoming_email.py

import logging
import urllib
import base64
import traceback
from google.appengine.ext import webapp
from google.appengine.ext import blobstore
from google.appengine.api import urlfetch
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp.mail_handlers import InboundMailHandler


class ReceiveEmail(InboundMailHandler):

    def receive(self, message):
        try:
            for filename, filecontents in message.attachments:
                if filecontents.encoding:
                    # data = filecontents
                    data = filecontents.decode()
                    # data = filecontents.payload
                    # data = filecontents.payload.decode()
                    # data = base64.b64decode(filecontents.decode())
                    # data = base64.b64decode(filecontents.payload)
                    # data = base64.b64decode(filecontents.payload.decode())

                upload_url = blobstore.create_upload_url('http://myapp.appspot.com/settings/saveItem/')
                form_fields = {'field_name': data}
                form_data = urllib.urlencode(form_fields)
                result = urlfetch.fetch(url=upload_url,
                                        payload=form_data,
                                        method=urlfetch.POST,
                                        headers={'Content-Type': 'application/x-www-form-urlencoded'})
                logging.info(result)
        except Exception, e:
            traceback.print_exc()

application = webapp.WSGIApplication([ReceiveEmail.mapping()], debug=True)


def main():
    run_wsgi_app(application)
if __name__ == "__main__":
    main()

My requirement is to create an entity corresponding to each mail with attachment. For this, I need to parse the attachment from the mail and upload it to blobstore. However, when I try to upload the attachment to blobstore, I get the following error:

The request's content type is not accepted on this URL.

As you can see in the commented code in "handle_incoming_email.py", I tried different methods (trial-and-error) to get the data correct, but to no avail.

Could someone guide me in fixing this!

Thanks!!!

2
  • Upload? Why not write it to the blobstore. Commented Jun 25, 2013 at 13:31
  • 1
    @voscausa : Writing files to the blobstore is deprecated as per the documentation. Moreover, I might need to post the file attachment as multipart/form-data to a 3rd-party API from my code. Commented Jun 25, 2013 at 18:58

1 Answer 1

6

I think this code sample will solve you problem. You probably need to use only encode_multipart_formdata function from this code. And do not forget to set properly content type.

class BlobstoreUpload(blobstore_handlers.BlobstoreUploadHandler):
  def post(self):
    upload_files = self.get_uploads('file')
    blob_info = upload_files[0]
    return self.response.write(blob_info.key())

  @classmethod
  def encode_multipart_formdata(cls, fields, files, mimetype='image/png'):
    """
    Args:
      fields: A sequence of (name, value) elements for regular form fields.
      files: A sequence of (name, filename, value) elements for data to be
        uploaded as files.

    Returns:
      A sequence of (content_type, body) ready for urlfetch.
    """
    boundary = 'paLp12Buasdasd40tcxAp97curasdaSt40bqweastfarcUNIQUE_STRING'
    crlf = '\r\n'
    line = []
    for (key, value) in fields:
      line.append('--' + boundary)
      line.append('Content-Disposition: form-data; name="%s"' % key)
      line.append('')
      line.append(value)
    for (key, filename, value) in files:
      line.append('--' + boundary)
      line.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
      line.append('Content-Type: %s' % mimetype)
      line.append('')
      line.append(value)
    line.append('--%s--' % boundary)
    line.append('')
    body = crlf.join(line)
    content_type = 'multipart/form-data; boundary=%s' % boundary
    return content_type, body


class UserProfile(webapp2.RequestHandler):
  def post(self):
    picture = self.request.POST.get('picture')

    # Write new picture to blob
    content_type, body = BlobstoreUpload.encode_multipart_formdata(
      [], [('file', name, image)])
    response = urlfetch.fetch(
      url=blobstore.create_upload_url(self.uri_for('blobstore-upload')),
      payload=body,
      method=urlfetch.POST,
      headers={'Content-Type': content_type},
      deadline=30
    )
    blob_key = response.content
Sign up to request clarification or add additional context in comments.

4 Comments

@Dmitry It worked for me too. Thank you Jithu for asking the question and Dmitry for the reply.
@Dmitry can u plz tell if we want to upload file from our local directory , then what should be in the argument 'files' ?
@omair_77 local directory? What do you mean? The sequence looks like: (input_name, filename, file_content_as_string)
@Dmitry i am trying to upload file from my PC to blobstore, using the code u have given , files are uploading fine but i am not receiving the blob.key in the response.content

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.