Save an email attachment to a designated bucket

Question:

App Engine allows one to listen to incoming emails. I’d like to then read attachments and write them to a GCS bucket. google.cloud.storage is not available in the standard environment, and cloudstorage, which is available, doesn’t allow writing in any other bucket but the default one.

I tried also in flexible env, but InboundMailHandler is not available in that case: “The App Engine Mail service is not available outside the standard environment” https://cloud.google.com/appengine/docs/flexible/python/migrating

Is there any way to write these files to a designated bucket, in a standard environment?

import logging
import webapp2
from google.appengine.ext.webapp.mail_handlers import InboundMailHandler

class LogSenderHandler(InboundMailHandler):
    def receive(self, mail_message):
        logging.info("Received a message from: " + mail_message.sender)
        plaintext_bodies = mail_message.bodies('text/plain')
        html_bodies = mail_message.bodies('text/html')

        if hasattr(mail_message, 'attachments'):
            for filename, filecontent in mail_message.attachments:
                # write filecontent to a bucket


app = webapp2.WSGIApplication([LogSenderHandler.mapping()], debug=True)
Asked By: nlassaux

||

Answers:

You can specify the bucket while writing in cloud storage.

from google.appengine.api import app_identity
bucket_name = os.environ.get('BUCKET_NAME',app_identity.get_default_gcs_bucket_name())

You can fetch the particular bucket by the above code. Then you can use this bucket to write in your cloud storage.
Keep in mind while writing file specify your filename as below:

file_name = '/' + 'BUCKET_NAME' + '/' + 'FILE_NAME'

For more detailed code regarding reading and writing, you can refer
Cloud Read/Write Documentation.

Detailed Read/Write Code: Github Google Cloud

Hope this answers your question!!

Answered By: skaul05

Based on the accepted answer, for a flask app, this is how you would do it:

In requirements.txt add google-cloud-storage

Flask==2.1.2
appengine-python-standard>=1.0.0
google-cloud-storage

In your main.py:

from flask import Flask, request
from google.appengine.api import mail
from google.appengine.api import wrap_wsgi_app
from google.cloud import storage
from datetime import date

app = Flask(__name__)

# Enable access to bundled services
app.wsgi_app = wrap_wsgi_app(app.wsgi_app)


@app.route("/_ah/mail/<path>", methods=["POST"])
def receive_mail(path):
    message = mail.InboundEmailMessage(request.get_data())

    print(f"Received greeting for {message.to} at {message.date} from {message.sender}")
    for content_type, payload in message.bodies("text/plain"):
        print(f"Text/plain body: {payload.decode()}")

        for filename, filecontent in message.attachments:
            print("Received attachment: ", filename)
            storage_client = storage.Client()
            bucket = storage_client.bucket("BUCKET NAME")
            blob = bucket.blob(f'{date.today():%Y-%d-%m}/{filename}')

            with blob.open("wb") as f:
                f.write(filecontent.decode())

    return "OK", 200

This is what my app.yaml looks like:

runtime: python39
app_engine_apis: true
service: email-service
inbound_services:
- mail
- mail_bounce
Answered By: Roshin Jay