2017/08/22

GAE で GCS 上のファイルを添付してメール送信する

前回までに、Calibre が設定された VM を起動すると Kindle 用の mobi ファイルを作成して GCS に保管するまでが設定できた。

今回と次回の2回に分けて、GCS に mobi ファイルが追加されたことをトリガーに、mobi ファイルをメール送信する仕組みを作る。

GCS (Google Cloud Storage) にファイルが置かれた際にアクションを起こすには、GCS の「オブジェクト変更通知 」を使用する。オブジェクト変更の通知先として、Google App Engine の URI を指定して、呼び出された GAE の処理の中で、 GCS 上の mobi ファイルを添付ファイルとしてメール送信する。

まずは GAE 側の処理を作るところから始める。オブジェクト変更通知を設定するには呼び出す先の URI を用意しておく必要がある。

ソースコードについては GitHub に公開してあるので全体についてはそちらをご参照。

GCS のオブジェクト変更通知では、変更のあったオブジェクト情報が POST されてくるので、GET の場合は特に何もしない処理をあえて入れておく。

@app.route('/sendmail', methods=['GET'])
def sayhello():
    """ Just say hello for GET request """
    return 'No action is evoked.'

@app.route('/sendmail', methods=['POST'])
def send2kind():
    """ Send email w/ attachment"""
    if 'X-Goog-Resource-State' in request.headers:
        resource_state = request.headers['X-Goog-Resource-State']
        if resource_state == 'exists':
            logging.info('Add message received.')
            add_obj = request.json
            bucket = add_obj['bucket']
            objname = add_obj['name']
            logging.info('%s/%s %s', bucket, objname, resource_state)
            # call to send email w/ attachment from the bucket
            cloudstorage_file = cloudstorage.open('/' + bucket + '/' + objname)
            recpaddr = os.environ.get('TOAD')
            sendaddr = os.environ.get('FRAD')
            logging.info('Sending to:' + recpaddr + ' from:' + sendaddr)
            mail.send_mail(sender=sendaddr,
                       to=recpaddr,
                       subject="Sending" + objname,
                       body="Sending mobi file",
                       attachments=[(objname, cloudstorage_file.read())])
            return objname + ' is added and sent to kindle'
        else:
            logging.info('Other state notification.'+resource_state)
            return 'Other state notification.'
    else:
        logging.info('Other post.')
        return 'Not correct request.'

まずはじめに、リクエストヘッダーを見て X-Goog-Resource-State の有無をチェック。あれば GCS のオブジェクト変更通知からの呼び出しとみて処理を行う。

今回の目的は、GCS にファイルが追加されたときにだけ作動すれば良いので、X-Goog-Resource-State の値が "exists" の場合だけ処理するようにする。この部分。

    if 'X-Goog-Resource-State' in request.headers:
        resource_state = request.headers['X-Goog-Resource-State']
        if resource_state == 'exists':

あとは POST されるデータの中から GCS のバケット名 (bucket) とファイル名 (name) を取得して、GCS の cloudstorage.open でファイルにアクセスできるようにしておく。

            add_obj = request.json
            bucket = add_obj['bucket']
            objname = add_obj['name']
            logging.info('%s/%s %s', bucket, objname, resource_state)
            # call to send email w/ attachment from the bucket
            cloudstorage_file = cloudstorage.open('/' + bucket + '/' + objname)

ここで、メールの送信先アドレスと、送信元アドレスを app.yaml に設定した値から取得する。この部分。

            recpaddr = os.environ.get('TOAD')
            sendaddr = os.environ.get('FRAD')

app.yaml にはこんな設定をしておく。もちろん、送信先メールアドレスには自分の Kindle ドキュメントを受け取れる @kindle.com のメールアドレスを指定する。From アドレスについては、 Kindle 側で受け取れる設定がされている送信元アドレスである必要もあるし、Google Cloud Console 上の GAE の設定にある「Email API の承認済み送信者」としても登録しておく必要がある。

env_variables:
  TOAD: '送信先メールアドレス'
  FRAD: 'Fromアドレス'

あとは Email API を使って添付ファイルを指定してメール送信をするだけ。メール本文はなんでもいい。

            mail.send_mail(sender=sendaddr,
                       to=recpaddr,
                       subject="Sending" + objname,
                       body="Sending mobi file",
                       attachments=[(objname, cloudstorage_file.read())])


ということで、project-id.appspot.com/sendmail でメール送信ができる環境が整った。

0 件のコメント:

コメントを投稿