Google Cloud上のSPAに問い合わせフォームを作る!SendGridによるメール送信

Google Cloud上のSPAに問い合わせフォームを作る!SendGridによるメール送信

Cloud StorageやApp EngineにデプロイしたSPA(Single Page Application)に問い合わせフォームを作りたいという方は多いはずです。

また、問い合わせページを作成したけど、どのようにメールを送信するべきか迷う方もいらっしゃると思います。

そういった方を対象に、Google Cloudの公式ドキュメントで推奨している方法を利用して、問い合わせフォームからメールを送信する方法を紹介します!

完成物のイメージです。

  • Cloud Functionsにメール送信用のAPIを公開(python)
  • SendGridのWebAPIを利用したメール送信
  • 1ヶ月12,000通のメールまで無料

概要

この記事で紹介する方法では、Cloud FunctionsにSendGridを利用したメール送信機能を持つアプリケーションをデプロイし、デプロイしたアプリケーションに対してSPAからリクエストを送信することで問い合わせ機能を実現します。

まず、SendGridやCloudFunctionsnを利用する理由や利点について説明します。

実装方法だけ知りたいという方はこの章は飛ばしてください。

SendGridとは

SendGridは、クラウドベースのSMTPプロバイダで、メール送信が可能なwebサービスです(公式サイト:https://sendgrid.kke.co.jp/)。

2021年6月では、Google CloudにはAWSのAmazon SESのようなサービスはありません(ないよね…?)。

そのため、メール送信方法として、公式ドキュメントにおいてもSendGrid, Mailgun, Mailjetといったサードパーティのメールサービスを利用した方法を紹介しています(例:SendGrid でのメールの送信)。

これらの中でも、下記の利点があるので、個人的にはSendGridの利用がおすすめです。

SendGridのgithubには、python, PHP, java, nodejsなどの言語ごとにリポジトリが作成されており、READMEに簡単なサンプルプログラムが公開されています。

READMEを読むだけで公式の推奨利用方法がわかるので、非常に助かりますね。

また、毎月12,000通まで無料で利用できるというのも非常に嬉しいです。

Cloud Functionsの利用理由

GCPの公式ドキュメントではCompute Engine(CE)を利用した方法を紹介していますが、CEではゼロスケーリングができないのでお金がかかってしまいます。

従量課金性+ゼロスケーリング可能+メール送信機能のみという特徴を考慮して、Cloud Functionsにメール送信アプリケーションをデプロイすることにしました。

ただ、CEやCloudFunctionsの他にAppEngineでも利用可能なはずなので、好きなプラットフォームで良いと思います。

メール送信機能の実装

それでは作成していきます、全体の流れは下記になります。

  1. SendGridのアカウント作成
  2. SendGridのAPIキーの取得
  3. プログラムの作成
  4. Cloud Functionsへのデプロイ

SendGridのアカウント作成

公式サイトからアカウントの作成を行います(https://sendgrid.kke.co.jp/)。

気をつけるべきポイントとして、アカウントの作成に約1営業日かかります

アカウントは早めに作成しましょう。

SendGridのAPIキーの取得

SendGridでアカウント登録後、アカウント名が送られてくるので、そのアカウントでログインします。

ログイン後、”Settings”タブから”API Keys”をクリックします。API Key Nameを入力して、Full Access権限でキーを作成します。

1. 左タブの”Settings”から”API Keys”を選択して、右上のボタンから作成
2. API keyの名前を入力して、”Full Access”でキーを作成

プログラムの作成

Cloud Functions上で動作するプログラムを作成します。

まず、プログラムはこちらです。リクエストのバリデーションなどは自分で追加してください。

from flask import Flask, request, make_response
import os
import sendgrid
from sendgrid.helpers.mail import Email, To, Content, Mail
def sample(request): # 取得したAPIKeyを環境変数SENDGRID_API_KEYにいれる SENDGRID_API_KEY = os.environ.get('SENDGRID_API_KEY') TO_EMAIL = os.environ.get('TO_EMAIL') FROM_EMAIL = os.environ.get('FROM_EMAIL') req_args = request.args sg = sendgrid.SendGridAPIClient(api_key=SENDGRID_API_KEY) message = ( 'from: {}\n' 'Email: {}\n' 'msg:\n{}'.format( req_args["name"], req_args["email"], req_args["msg"]) ) mail = Mail( Email(FROM_EMAIL), To(TO_EMAIL), "Email from Cloud Functions", Content("text/plain", message) ) _ = sg.client.mail.send.post(request_body=mail.get()) return make_response('', 200)
if __name__ == '__main__': app = Flask(__name__) @app.route('/sample', methods=['GET']) def call_function(): return sample(request) app.run(debug=True, host='0.0.0.0', port=5000)

Cloud Functionsへのデプロイで必要なrequirements.txtは下記です。

blinker==1.4
click==8.0.1
Flask==1.0.2
itsdangerous==2.0.1
Jinja2==3.0.1
MarkupSafe==2.0.1
mccabe==0.6.1
pycodestyle==2.7.0
pyflakes==2.3.1
python-http-client==3.3.2
sendgrid==6.7.0
starkbank-ecdsa==1.1.1
toml==0.10.2
Werkzeug==2.0.1

あとは、ローカル環境で動作確認後、Cloud Functionsにデプロイしましょう。

下記では.env.yamlを利用してAPIキーを環境変数に代入していますが、SecretManagerを利用するほうがセキュリティ的には正しいと思います。

# ローカル環境でのテストリクエスト例
$ curl -v "http://localhost:5000/sample?email=test@gmail.com&msg=hoge&name=huga"
# 問題がなければ、Cloud Functionsへデプロイ
# デプロイコマンドの例
$ gcloud functions deploy sample_for_sendgrid \ --runtime python38 \ --trigger-http \ --allow-unauthenticated \ --region=us-central1 \ --env-vars-file .env.yaml
# Cloud Functionsに対して、動作確認
$ curl -v "https://.../sample?..."

SPAとの連携

連携というほどのものではありませんが、、、

SPAの問い合わせフォームのボタンを押したときに、上記で作成したCloud FunctionsのエンドポイントへGETリクエストを送信するように変更しましょう。

上記では、クエリパラメータとしてemail, msg, nameを適当に使いましたが、このあたりは各自適当に変更してください。

まとめ

この記事では、Cloud Functions + SendGridを利用してメール送信機能を持つAPIを作成しました。

SPAから作成したエンドポイントに対してリクエストを送ることで、問い合わせフォームからメールを送信することが可能になります。

Google検索でGCP上のメール送信方法を調べると、Firebase+gmailを利用した方法が多く見られます。ただ、Google Cloudで完結可能なので、わざわざFirebaseを利用する必要はないです(実際にはFirebaseもGoogle Cloud上で動作していますが…)。

また、Gmailのアカウント情報+信頼性の低いアプリケーションからのログインを許可する必要があるので、セキュリティ的にもよろしくないかなと個人的には考えています。