9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Gaiax GroupAdvent Calendar 2018

Day 14

自前フォームをGoogle フォームとS3を利用してサーバーレスに構築する

Last updated at Posted at 2018-12-14

この記事は、Gaiax Group Advent Calendar 2018 の14日目の記事です。

はじめに

Gaiaxでは年に2回社員全員が集まり会社の状況や方針について確認し、各事業の成果などを共有する社員総会というものがあります。
今回の社員総会では、「Gaiax Most Valuable Story」と称して、一緒に目標を達成した仲間や、お世話になった人に感謝の手紙を書くという取り組みを行うことになりました。
この一連のシステム開発について書いて見ようと思います。

実現したいことは以下のような感じです。

  • それっぽいフォームで手紙を書くことができる
  • 宛名、宛先メールアドレス、差出人名、差出人メールアドレス、メッセージが入力できる
  • フォーム送信時
    • 内容を保存する
    • 宛先へ手紙が書かれたことを通知(本文は後日送信)
  • 社員総会時に手紙の内容をメールで送信

今回はこの要件のうち、フォーム送信時までを次の仕組みで実現してみます。
(社員総会時に手紙の内容をメールで送信はまたのちほど)

  • それっぽい自前フォームの送信先をGoogle フォームにする
  • 送信をトリガーにして、Google App Scriptで宛先へ手紙が書かれたことを通知する
  • 自前のフォームはS3で静的ホスティングする

Google フォームの作成

まずは、Google フォームを作成します。こんな感じで、名前とメールアドレスは記述式、メッセージは段落で作成しました。全てのデータが必要なのですが、Google フォームで必須チェックにかかってもそれをキャッチできないので、ここでは必須項目の設定をせずフロント側で対応します。
スクリーンショット 2018-12-14 23.20.31.png

この時フォームの送信からリンクを取得し、回答画面でformタグにあるactionと各入力項目のnameをメモしておきます。(末尾を変更しています)

  • action
スクリーンショット 2018-12-14 23.30.55.png
  • name
スクリーンショット 2018-12-14 23.33.50.png

inspecterで要素を選ぶと見つけやすいです。

自前のフォームの作成

続いて自前のフォームを作成します。こんな感じに普通のフォームを作成、先ほどメモしたactionと各入力項目のnameを設定します。
これで自前フォームからのPOSTをGoogle フォームで受け取ることができるようになりました。

form.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>感謝の手紙</title>
    <link rel="stylesheet" type="text/css" href="./assets/css/style.css">
  </head>
  <body>
    <div id="formWrapper">
      <form action="https://docs.google.com/forms/u/1/d/e/1FAIpQLSd2zHuravWpQfdS0fwUiaPD6r2l8TQN-yzArPDfXXXXXXXXXX/formResponse">
        <div class="letter">
          <!-- 宛先と宛名 -->
          <div class="toEmail">
            <input id="toEmail" type="email" name="entry.214573XXXX" placeholder="宛先メールアドレスを入力" required/>
          </div>
          <div class="toName">
            <input id="toName" type="text" name="entry.119565XXXX" placeholder="宛名を入力" required/>
          </div>

          ~~ 省略 ~~

        </div>
      </form>
    </div>
  </body>
</html>

バリデーションについては厳密なバリデーションは必要ないため、requiredを利用してフロント側で対応しました。こちらも紆余曲折ありましたが、また別の機会で。

S3での静的ホスティング

今回は、ページ数も少なく動的な要素もないためAmazon AWSのS3を利用して静的ホスティングで配信してみます。
まずはAWSのコンソールからS3バケットを作成します。バケット名を決めて、次へ進みます。
スクリーンショット 2018-12-15 0.25.54.png

オプションの設定はなにも変更せず進み、アクセス許可の設定で「このバケットのパブリックバケットポリシーを管理する」内にある2つの項目のチェックを外します。(後ほどバケットポリシーを追加したら、新規のパブリックバケットポリシーをブロックする (推奨)はチェックを戻します。)
これでバケットが作成できました。
スクリーンショット 2018-12-15 0.40.04.png

続いてバケットポリシーで、匿名ユーザーへの読み取り専用アクセス許可の付与をします。examplebucketは作成したバケット名を設定します。

バケットポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AddPerm",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::examplebucket/*"
        }
    ]
}

これで、S3でのバケット公開設定が完了しました。
先ほど作成した自前フォームのファイルをアップロードし、ファイルの概要内にあるリンクをクリックするとフォームが閲覧できると思います。

Google Apps Script(GAS)でのメール通知

さて次は、フォームでメッセージが送信された際に宛先メールアドレスに対して手紙が書かれたことを通知したいと思います。メッセージの内容はここではあえて記載せず、社員総会後にまとめて送信する形です。

GASをこんな感じに書きます。通知メールは雰囲気をだしたかったので、HTMLメールにし、HTMLは外部ファイルから読み込んでいます。
受け取った宛先メールアドレスをaddressに入れtoに設定します。また、返信されても困るので、noreplyオプションをつけています。

notify.js
function submitForm(e){
  FormApp.getActiveForm();
  
  var itemResponses = e.response.getItemResponses();
  var address = itemResponses[0].getResponse();
  var html = HtmlService.createHtmlOutputFromFile("message").getContent();

  MailApp.sendEmail({
    to: address,
    subject: 'Gaiax Most Valuable Story からのお知らせ',
    body: '感謝の手紙\n\n誰かがあなたに感謝の手紙を送ったようです。\n送られた手紙は来年の社員総会後に届きます。\n今年1年を振り返り、あなたも誰かに感謝の手紙を書いてみませんか?\n\nGaiax MVS運営', 
    htmlBody: html,
    noReply: true
  });
}

よくある例にはFormApp.getActiveForm();の記載はないのですが、これを書いて権限の承認をしないと、メール送信ができません。他の部分が動かなくてもいいので、これを書いたらスクリプトエディタで実行し、権限の承認をしておきます。

message.html
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <style type="text/css">
    p,h1 {text-align:center}

    a {
      text-align: center;
      display: block;
      margin: 50px auto;
      width: 200px;
    }

    .content {
      margin: 10px auto;
      width: 350px;
    }
    </style>
  </head>
  <body>
    <h1>感謝の手紙</h1>
    <div class="content">
      <p>誰かがあなたに感謝の手紙を送ったようです。</p>
      <p>送られた手紙は1月の社員総会後に届きます。</p>
      <p>今年1年を振り返り、あなたも誰かに感謝の手紙を書いてみませんか?</p>
      <a href="https://s3-ap-northeast-1.amazonaws.com/XXXXXXXX/index.html" class="square_btn" style="text-align: center;display: block;margin: 50px auto;width: 200px;padding: 0.3em 1em;text-decoration: none;background-color: #FFA700;color: #FFF;border: solid 2px #FFA700;border-radius: 3px;transition: 0.4s">手紙を書く</a>
    </div>
  </body>
</html>

簡単なCSSでしたので、ファイル内に記載しています。Gmailで受信テストをしていたのですが、Gmailでは一部のstyle要素が落とされてしまうためインラインで指定をしてたりします。

続いてトリガーの設定です。リソースをフォームからに設定し、イベントの種類をフォーム送信時に設定します。
スクリーンショット 2018-12-15 1.12.45.png

これで、手紙送信時に宛先へメールでの通知が自動送信されるようになりました。

そしてこんな感じのできあがりになりました。自分で言うのもあれですが、なかなかそれっぽいフォームになったと思います :clap:
Image from Gyazo

スクリーンショット 2018-12-15 1.30.43.png

まとめと感想

長くなってしまいましたが以上となります。
普段あまり実装をしないので、なかなか時間がかかってしまいましたが、たのしく構築することができました。間違いなどあれば、ご指摘していただけると嬉しいです。
今回書ききれなかったことは、また別の記事にでもしようと思います。ここまで読んでいただき、ありがとうございました。

それではよいクリスマスをお過ごしください。
:christmas_tree: Happy Merry X'mas!! :tada:

9
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?