📧

Google Sheets と Apps Script で最低限の List-Unsubscribe のハンドラを作る

2024/05/08に公開

この記事は、メールの配信を自前のソフトウェアで実施しており、Gmail の メール送信者のガイドライン へのできるだけ簡単な対応を検討している人向けのものです。

https://support.google.com/a/answer/81126?hl=ja

はじめに

Gmail の メール送信者のガイドライン により、メールマガジンの類を作る場合に SPF、DKIM、DMARC の設定をすることに加えて、List-Unsubscribe ヘッダによるワンクリックでの登録解除に対応する必要が出てきました。

登録解除のための List-Unsubscribe ヘッダは古い RFC 2369 の仕様では、mailto スキームを使っても良かったのですが、Google のガイドでは RFC 8058 のワンクリック解除への対応も要求されており、こちらの場合 https による登録解除が必須になっています。

しかし、個人事業レベルでこの対応のためにわざわざサーバを立てるのは大変なので、最低限仕様を守るために Google Sheets と、Google Apps Script の Web Application を用いてメール配信解除の受付をする方法を検討しました。

https://developers.google.com/apps-script/guides/web?hl=ja

処理自体は動くレベルになったので情報を共有します。

ただし、Gmail においてどういう場合に「配信停止」のリンクが表示されるのかは不明で、これらの実装を行っても必ずしも登録解除のリンクが表示されないことを留意してください。

基本的な仕組み

Google Sheets に登録解除希望者の情報(メールアドレス)を書き込むシンプルな Web Application を Apps Script で作成して、登録解除の要求を Google Sheets に記録します。

メールのヘッダはこんな感じになります

List-Unsubscribe: https://script.google.com/macros/s/XXXXXXXXXX/exec?from=someone%40example.com
List-Unsubscribe-Post: List-Unsubscribe=One-Click

XXXXXXXXXX の部分は Apps Script の Web Application をデプロイしたときに生成される Deployment ID になります。
URL の from=someone%40example.com の部分で誰が登録解除を要求しているのかを判別します[1]

サーバ(リクエスト受付)側実装の手順

1. 記録用のスプレッドシートを作成します。

今回の例では Unsubscribe-Requests という名前のシートを作成しています。
スプレッドシートの URL は、次のテップで使いますので記録してください。

2. スプレッドシートにデータを書き込むための Web Application を Apps Script で作成します

  1. スプレッドシートのメニュー 拡張機能 > Apps Script から Apps Script 編集のプロジェクトを立ち上げます。
  2. プロジェクト名は適当で構いません。(例: List-Unsubscribe-Handler
  3. スクリプトの Code.gs に以下を記載します:
    function doPost(e) {
      const url = "https://docs.google.com/spreadsheets/d/YYYYYYYYYY/edit#gid=0";
      const ss = SpreadsheetApp.openByUrl(url);
      const sheet = ss.getSheets()[0];
      const params = {
        "timestamp": new Date(),
        "from": e.parameter.from
      };
      sheet.appendRow(Object.values(params));
      return ContentService.createTextOutput('sccess');
    }
    
    function doGet(e) {
      return doPost(e)
    }
    
    url の値として、先ほど作成したスプレッドシートのURLを記載してください。

このスクリプトは単純にリクエストのクエリに指定した from パラメータの値(=配信停止希望のメールアドレス)とリクエスト受信日時をスプレッドシートの末尾に記録します。

List-Unsubscribe のフレームワークのみに対応するのであれば、リクエストは POST メソッドで送信されることになっているので、POST のハンドラである doPost() だけあればよいのですが、メール本文中のリンクからもワンクリックで登録解除できるようにするために、GET メソッドのハンドラ、 doGet() も作成しています。

3. Web Application をデプロイします

デプロイの際の手順はほぼ、以下のページに書いてある手順と同じです:
https://zenn.dev/suzuky/articles/6ad0cb1a54823f

  1. スクリプトを Web Application としてデプロイしてください。
  2. RFC 8058 の要件に従い、リンクはユーザー認証を要求する設定にしてはいけないので、Who has access の設定は Anyone にしてください。
  3. 最初のデプロイ時には、アクセス権の付与のためのダイアログが表示され、「Google hasn't verified this app」などの(ちょっと怖い)確認画面が出ますが、「Advanced」のリンクをたどって、処理を継続してください。

成功すると Web Application にアクセスするための URL が生成されます。
通常、次のような形式です。

https://script.google.com/macros/s/XXXXXXXXXX/exec

4. 動作確認

cURL で動作確認してみましょう

RFC 8058 に従うワンクリック登録解除の確認(POST で body が application/x-www-form-urlencoded になるパターン[2]

curl -L -d "List-Unsubscribe=One-Click" "https://script.google.com/macros/s/XXXXXXXXXX/exec?from=sample%40example.com"

RFC 8058 に従うワンクリック登録解除の確認(POST で body が multipart/form-data になるパターン [3]

curl -L -F "List-Unsubscribe=One-Click" "https://script.google.com/macros/s/XXXXXXXXXX/exec?from=sample%40example.com"

本文中のリンクからの登録解除の確認(GET になるパターン)

curl -L "https://script.google.com/macros/s/XXXXXXXXXX/exec?from=sample%40example.com"

スプレッドシートにデータが記載されれば成功です。

メール送信時の処理

お使いのシステムで、List-Unsubscribe のヘッダに先程設定した URL を記載します。
この際、 from パラメータはURLのクエリ文字列として埋め込みます。
List-Unsubscribe のフィールドは、送信先ごとに異なる値になることに気をつけてください。

List-Unsubscribe: https://script.google.com/macros/s/XXXXXXXXXX/exec?from=someone%40example.com
List-Unsubscribe-Post: List-Unsubscribe=One-Click

List-Unsubscribe に対応したメーラを使っている場合、この情報を元に仕様に従った POST メッセージが発行されます[4]

また、メールの本文中に退会のリンクを記載することが推奨されていますので、同じURLを記載しておきます。

メール配信を止めたい場合は次のURLにアクセスしてください:
https://script.google.com/macros/s/XXXXXXXXXX/exec?from=someone%40example.com

通常、この本文中のリンクをクリックすると GET メソッドで Web Application が呼び出されます。

この仕組みの運用

メールを配信するまえには、先程のスプレッドシートを確認して、退会要求が来ていないか確認してください。
このあたりの処理を自動化する仕組みを作ることも出来ますが、この記事の範囲外とします。

脚注
  1. メールアドレス someone@example.com@ の部分は予約文字なので%エンコードしています。 ↩︎

  2. メール送信者のガイドライン によると、Gmail はこちらの動作になります。 ↩︎

  3. RFC 8058 で推奨されている挙動はこちらです。 ↩︎

  4. どんなメッセージになるかは メール送信者のガイドライン の例を参照してください。 ↩︎

Discussion