Googleフォームの自動応答メールを綺麗で豪華にする方法【GAS】

現在のGmailはメルマガ配信などでも使える、企業が配信するような豪華なレイアウトの綺麗なメールを作成することが出来るようになっています。しかしこれはGmailのUI上での話。

Google Formの自動応答メールでも使えたら、ユーザーに綺麗で豪華な自動応答メールを送ることが出来、簡素でダサいメールとオサラバできます。そこで今回はこのテーマにチャレンジしてみました。

今回利用する素材

以前にも単純な自動応答のメールや、さらにHTML + CSSでレスポンシブなスマホ対応のメール作成は以下のエントリーで行っています。今回はさらにHTML Service差し込みテクニックを使って、より豪華でリッチなものに仕上げています。

差し込みテクニックについてはGASでRSS配信を行うでも、XML生成時に使っているテクニックで、今回はこれをHTMLにて行っています。

Google Apps Scriptでレスポンシブメールを送ってみた【GAS】

新しいGoogle Formを業務に活用する – その②

Google Apps ScriptでRSSを配信する【GAS】

事前準備

Geminiでレイアウトを作成する

今回のレイアウトはGeminiのCanvas機能で作成してもらっています。これがそのまま使えるわけではないのですが、生成されたものを微調整した上で、差し込みテクニックが出来るように改造を施します。

当初のプロンプトとしては以下のようなものを入れています。

GoogleフォームにGASを記述して、フォーム送信時に自動応答でメールを返すものを考案中です。その際のメール本文のデザインについて、簡素なメールではなく豪華なデザインのメールを作りたい。
以下のような要件に合うHTMLのデザインを作ってください。

#Gmailで送信するので、CSSはすべてインラインで対応
#冒頭に「ありがとうございました」から始まる、送信に関してのお礼の文章
#中盤に入力内容をそのまま返すテーブル(2列)
##タイトル1列目は項目名という名前
##タイトル2列目は入力値という名前
#終盤は、自動応答メールであるので返信出来ない旨の内容と、企業の署名を入れる

誠にありがとうございました部分がセンタリングされていたのでここを微調整してもらい、とりあえずの完成。このHTMLコードをGASのメール送信時の土台として利用します。

Gmailで使う場合タグに対してのCSSはインラインにしないと反映しないことがあるので、原則インラインにCSSを記述するように指示を与えています。

図:GeminiのCanvasでレイアウトを作る

GASのグローバル設定

Googleフォームのスクリプトエディタを開いて以下の値を入力しておきます。

  • フォームファイルのIDをformid変数に入れておきます。
  • メールを受け取るこちらがわの受け口のメールアドレスをmaster変数に入れておきます。
  • titleはメールのSubjectになるもの。Gmailでフィルタしてる場合はフィルタしやすいプレフィックスをいれておくとベスト

今回のフォームは送信後にデータを受け取ったら、Form内部からはデータを常に消去しているため、その操作の為にformidが必要になっています。

図:グローバル設定を用意して記述

フォームの設定

前述で常にForm内部からデータを消去してるのは、スプレッドシートへと書き込みをさせているため。フォームに残す必要が無いので、このような処理にしています。

故にフォームに対して以下の手順でスプレッドシートへのリンクをしておきます。

  1. 回答タブを開く
  2. スプレッドシートにリンクをクリックする
  3. 新しいスプレッドシートを作成を選んで、作成をクリック
  4. 以降送信データはスプシに蓄積されるので、このスプシは誰にも公開しないでアクセス権は限定アクセスにしておきましょう(情報漏洩に繋がります)。

これはセキュリティの為にこのような仕組みにしており、万が一フォームが漏洩したとしてもデータはスプシ側にあり、フォームには残さないので防御策になります。

また今回は、名前、メアド、タイトル、本文の4つのみをフォームに用意してるのでソレに合わせてレイアウト側も変更を後述で行っています。

図:データはスプシ蓄積にのみにする

コードと実行結果

注意点

今回の手法でいくつか過去に使っていたコードのままにしておいた箇所が原因なのか?メールが送信されずにブロックされるという現象が発生するようになりました。

そこで調査してみたところ、以下の部分を改善することで届くようになったため、過去のコードから該当する部分を削除したり修正しています。

  • template.htmlにおいて、改行コードを生かすために<?!= ?>としていた場所は、強制出力ではなく<?= ?>に修正しました
  • おなじくtemplate.htmlにおいて、white-space: pre-wrap;をrowdata[3]の部分のStyleに追加しました。
  • MailAppにて、nameを使っている部分は削除しました。noReplyはそのままにしてあります。
  • フッター部分のリンク等があるとブロックされやすいので丸っと削除した

フッター部分の削除は特に効果があったのですが、以下のようなものがあったので丸っと削除しました。

<!-- フッター -->
<tr>
  <td style="padding: 30px 40px; background-color: #f0f0f0; border-bottom-left-radius: 8px; border-bottom-right-radius: 8px;">
    <p style="margin: 0 0 15px; font-size: 12px; color: #888888; text-align: left;">
      ※このメールはシステムからの自動送信です。ご返信いただいてもお答えできませんので、ご了承ください。
    </p>
    <hr style="border: 0; border-top: 1px solid #dddddd; margin-bottom: 20px;">
    <p style="margin: 0; font-size: 14px; color: #555555; line-height: 1.7;">
      <strong>officeの杜</strong><br>
      ✉️ <a href="mailto:メールアドレス">お問い合わせを行う</a><br>
      🌍️ <a href="ウェブサイトのURL" style="color: #4a90e2; text-decoration: none;">ここにウェブサイトのURL</a>
    </p>
  </td>
</tr>

図:メールブロックされた事例

ソースコード

GAS側コード

基本スタイルはレスポンシブメール送信時や前回のフォームからの自動応答と同じです。しかし今回の変更に伴って、以下のような変更点を加えています。

  • 複数同時送信を考慮してLockServiceを使った排他制御処理を入れて同時に処理が進まないようにしています。
  • フォームデータを配列に順に格納したら、form.deleteAllResponses()フォームデータを全削除するようにしています。全削除したくない場合はこのコードは不要です(多数問い合わせがある場合は外しておいたほうが良いでしょう)。
  • HtmlService.createTemplateFromFileにてHTMLを生成し、同時にoutput.dataに対して受け取ったフォームデータを格納してHTML側に渡しています。
  • HTML変換と差し込み結果を受け取ったらあとはhtmlbodyとしてメール本文として指定して送るだけ

他にもエラー時やfinallyでロック解除を明示的に行うなど細かい処理を入れて、完成です。あらかじめ何か適当な関数を作って実行しておき、認証を完了しておきましょう

排他制御でGoogle Apps Scriptを安全に実行【GAS】

//自動応答メールを送信する
function sendForms(e) {
  //フォームを取得する
  const form = FormApp.openById(formid);

  //変数を宣言する
  let data = []; //送信データを格納する

  //メール送信設定
  let user = "";

  //ロックを取得する
  const lock = LockService.getScriptLock();

  //30秒間のロックを実施する
  lock.tryLock(30000);

  try{
    //送信データを取得する
    const formdata = e.response.getItemResponses();  

    //入力項目を取得する
    for (let i = 0; i < formdata.length; i++){
      //入力項目名を取得する
      let titlehead = formdata[i].getItem().getTitle();

      //ユーザーのメールアドレスを取得する
      if(titlehead == "メールアドレス"){
        //メアドを格納する
        user = formdata[i].getResponse();
      }

      //本文の改行コードを変換する
      if(titlehead == "お問い合わせ内容"){
        //本文を取得する
        let tempres = formdata[i].getResponse();

        //配列に追加
        data.push(tempres);
      }else{
        //配列に追加
        data.push(formdata[i].getResponse());
      }
    }

    //フォームデータをクリアする
    form.deleteAllResponses();

    //HTMLファイルを取得する
    let output = HtmlService.createTemplateFromFile('template.html');

    //変数データを付けて渡す
    output.data = JSON.stringify(data);

    //HTML出力
    let result = output.evaluate();

    //変換結果を受け取る
    let htmlbody = result.getContent()

    //自動応答メールを送る
    MailApp.sendEmail({
      to: user,
      bcc: master,
      subject: title,
      htmlBody: htmlbody,
      noReply: true
    });
  }catch(e){
    //ロック取得できなかった時の処理等を記述する
    let checkword = "ロックのタイムアウト: 別のプロセスがロックを保持している時間が長すぎました。";
   
    //通常のエラーとロックエラーを区別する
    let msg;
    if(e.message == checkword){
      //ロックエラーの場合
      msg = "申請処理がタイムアウトしました。";
    }else{
      //ソレ以外のエラーの場合
      msg = e.message;
    }  

    //申請者にメール通知をする
    MailApp.sendEmail({
      to: data[0],
      bcc : master,
      subject: '申請エラー',
      body:msg,
      noReply: true
    });
  }finally{
    //ロックを開放する
    lock.releaseLock();
  }
}

HTML側コード

Geminiで生成したテンプレートをGASのスクリプトエディタでtemplate.htmlとして保存。これに対していくつかの改造を加えます。

  • メールアドレスなどの4項目を表示するように項目を用意
  • 文末の署名欄の会社名やメアド、URLなどを変更しておく
  • 途中でスクリプトレットにてHTML生成時に同時に送られるデータを受け取るものを記述しておく。以下のようなものがそれになります。文末に<? ?>を記述することで、このタグの間でデータを差し込むことが出来ます。
    <? var rowdata = JSON.parse(data); ?>
    
    <? ?>
  • 各項目に差し込む部分は、前述のスクリプトレットで受け取ったrowdataの中身を割り当てます。以下は配列の1個目を割り当てるようにしています。
    <?= rowdata[0] ?>
  • ただし、長文回答欄だけは改行が可能なのですが、そのまま受け取ると改行コードが消えるので、styleとしてwhite-space: pre-wrap;を追加しています

このtemplate.htmlをGAS側で出力するときに、GAS側でFormから受け取ったデータを配列にしてoutput.dataとして送り込んでるのでこのような差し込みが可能になっています。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>お問い合わせありがとうございます</title>
</head>
<body style="margin: 0; padding: 0; background-color: #f4f4f4; font-family: 'Hiragino Kaku Gothic ProN', 'ヒラギノ角ゴ ProN W3', Meiryo, メイリオ, Osaka, 'MS PGothic', sans-serif;">

  <!-- メインコンテナ -->
  <table width="100%" border="0" cellpadding="0" cellspacing="0" style="background-color: #f4f4f4;">
    <tr>
      <td align="center">
        <table width="600" border="0" cellpadding="0" cellspacing="0" style="max-width: 600px; margin: 20px auto; background-color: #ffffff; border-radius: 8px; box-shadow: 0 4px 10px rgba(0,0,0,0.1);">

          <!-- ヘッダ -->
          <tr>
            <td align="left" style="padding: 40px 40px; background-image: url('https://images.unsplash.com/photo-1557683316-973673baf926?q=80&w=1200&auto=format&fit=crop'); background-size: cover; background-position: center; border-top-left-radius: 8px; border-top-right-radius: 8px;">
              <h1 style="margin: 0; color: #ffffff; font-size: 28px; font-weight: bold; text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000, 3px 3px 5px rgba(0,0,0,0.5);">お問い合わせいただき、<br>誠にありがとうございました</h1>
            </td>
          </tr>

          <!-- ボディ -->
          <tr>
            <td style="padding: 30px 40px;">
              <p style="margin: 0 0 20px; font-size: 16px; line-height: 1.8; color: #333333;">
                この度は、フォームにご入力いただき誠にありがとうございます。<br>
                以下の内容で送信を承りましたので、ご確認ください。
              </p>

              <!-- 入力データ -->
              <table width="100%" border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse; border: 1px solid #dddddd;">
                <thead>
                  <tr>
                    <th style="background-color: #ddeeff; padding: 12px 15px; border: 1px solid #dddddd; text-align: left; font-size: 16px; color: #333333; width: 30%;">項目名</th>
                    <th style="background-color: #ddeeff; padding: 12px 15px; border: 1px solid #dddddd; text-align: left; font-size: 16px; color: #333333;">入力値</th>
                  </tr>
                </thead>
                <tbody>
                  <?
                    var rowdata = JSON.parse(data);
                  ?>
                    <tr>
                      <td style="padding: 12px 15px; border: 1px solid #dddddd; font-size: 14px; color: #555555; background-color: #fcfcfc; vertical-align: top;">メールアドレス</td>
                      <td style="padding: 12px 15px; border: 1px solid #dddddd; font-size: 14px; color: #555555; background-color: #fcfcfc; vertical-align: top;"><?= rowdata[1] ?></td>
                    </tr>
                    <tr>
                      <td style="padding: 12px 15px; border: 1px solid #dddddd; font-size: 14px; color: #555555; vertical-align: top;">お名前</td>
                      <td style="padding: 12px 15px; border: 1px solid #dddddd; font-size: 14px; color: #555555; vertical-align: top;"><?= rowdata[0] ?></td>
                    </tr>
                    <tr>
                      <td style="padding: 12px 15px; border: 1px solid #dddddd; font-size: 14px; color: #555555; vertical-align: top;">タイトル</td>
                      <td style="padding: 12px 15px; border: 1px solid #dddddd; font-size: 14px; color: #555555; vertical-align: top;"><?= rowdata[2] ?></td>
                    </tr>
                    <tr>
                      <td style="padding: 12px 15px; border: 1px solid #dddddd; font-size: 14px; color: #555555; vertical-align: top;">お問い合わせ内容</td>
                      <!-- 改行がクリアされないよう強制出力で対応する -->
                      <td style="padding: 12px 15px; border: 1px solid #dddddd; font-size: 14px; color: #555555; vertical-align: top; white-space: pre-wrap;"><?= rowdata[3] ?></td>
                    </tr>
                    
                  <? ?>
                </tbody>
              </table>

              <p style="margin: 30px 0 0; font-size: 16px; line-height: 1.8; color: #333333;">
                担当者より追ってご連絡いたしますので、今しばらくお待ちくださいませ。
              </p>
            </td>
          </tr>

        </table>
      </td>
    </tr>
  </table>

</body>
</html>

実行結果

フォームを公開して、自身のブログに貼るなりしてみて、送信テストを行います。実際に送ってみるとHTMLにデータを差し込んだ結果がメール本文に表示され、画像やリンクなどCSSが無事に効いてることを確認します。

Gmailで使えるタグは限定的なのと、外部のCSSは読み込めない仕様なので、インラインCSSにするか?CSSだけ別途HTMLとして用意して取得時に合成するなどのテクニックが必要です。

あとは気に食わない点があれば、少しずつGeminiに問い合わせしてデザインチューニングすると良いでしょう。企業ロゴを入れてみたり、ヘッダの背景に画像を指定したり、テーブルももうちょっとマシなものにしてみたりと色々活用することが出来ると思います。

もちろんスマホ対応としてるので、スマホでの見え方もチェックしておくと良いでしょう。

図:実際に送信してみた様子

関連リンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)