【第446回】 MC Engagement の「カスタム購読取り消しページ」の作成方法
Marketing Cloud Engagement に標準で用意されている「購読取り消しページ」(実行ページ)は、以下のような見た目になっており、残念ながらデザインや内容を編集することができません。

そこで今回の記事では、CloudPages を利用して「カスタム購読取り消しページ」を作成する方法をご紹介します。
はじめに、この作業を行う前提として「購読者キー(Subscriber Key)」を暗号化します。この暗号化は必須ではありませんが、購読者キーを生のパラメータとして扱うよりも、セキュリティ面を考えると暗号化しておくことをおすすめします。
実装自体はとてもシンプルですので、ぜひ一緒に試してみましょう。
今回は、以下の AMPscript を使用します。
キー管理について
この暗号化処理では、以下の 3 種類のキーが利用されます。
対称キー(一般的に「パスワード」と呼ばれるもの)
Salt(ソルト)キー
初期化ベクトル(Initialization Vector : IV)キー
ただし、② Salt キーと ③ IV キーについては、
どのような外部キー(値)を指定しても処理自体は問題なく動作します。
そのため、本記事では ① 対称キーのみを使用し、
②・③ については今回は考慮しません。
対称キーの作成
1. セットアップ画面から 「キー管理」 を選択し、「作成」 をクリックします。

2. まずは 「対称キー」 を作成します。
外部キーは入力して指定しても、空欄のままでも構いません。
※ 空欄の場合は、UUID で自動生成されます。

3. 次に 「事前共有キー」 を入力します。
以下のようなフリーの 16 進数自動生成サイトを利用すると便利です。

4. 表示された行の中から任意の値を 1 つコピーし、キー管理画面に戻って 「事前共有キー」 の入力欄へ貼り付け、保存します。

5. 保存が完了すると、キー一覧に 「対称キー(=外部キー)」 が表示されます。この値は、以下のデータエクステンションで使用します。

データエクステンションへのキーの格納
生成したキーを データエクステンションに格納するのは、セキュリティを考慮した運用のためです。
1. データエクステンションの作成
データエクステンション名:SecretKey_DE
項目:
Name
Value

2. レコードの登録
Name:UnsubscribeKey
Value:先ほど作成した 対称キー

CloudPages 側(購読取り消し実行ページ)
まず、CloudPages にページを作成します。
以下の通り、HTML で直接作成しても問題ありませんし、
画像ブロックやフリーフォームブロックを利用しても構いません。
以下は、トークン取得から購読解除処理までを行う AMPscript + HTML です。(※コードはそのまま利用できます)
%%[
/* ========== 1. トークン取得 ========== */
VAR @token, @secretKey, @subscriberKey
VAR @status, @BU_MID
VAR @subscriber, @cid, @options, @save, @result
VAR @update_sub_status, @update_sub_errorcode
SET @token = QueryParameter("token")
IF EMPTY(@token) THEN
Redirect("https://YOUR-DOMAIN/errorpage")
ENDIF
/* + → スペース対策(URLパラメータで空白化されるケース) */
SET @token = Replace(@token, " ", "+")
/* ========== 2. シークレットキー取得 ========== */
SET @secretKey = Lookup("SecretKey_DE", "Value", "Name", "UnsubscribeKey")
/* ========== 3. 復号処理 ========== */
SET @subscriberKey = DecryptSymmetric(
@token,
"AES",
@secretKey,
@null,
"0000000000000000", /* IV */
@null,
"00000000000000000000000000000000", /* Salt */
@null
)
/* ========== 4. トークン検証 ========== */
IF EMPTY(@subscriberKey) OR IndexOf(@subscriberKey, "DecryptSymmetric") > 0 THEN
Redirect("https://YOUR-DOMAIN/errorpage")
ENDIF
/* ========== 5. 登録解除処理(All Subscribers) ========== */
SET @status = "Unsubscribed"
SET @BU_MID = AuthenticatedMemberID()
SET @subscriber = CreateObject("Subscriber")
SetObjectProperty(@subscriber, "SubscriberKey", @subscriberKey)
SetObjectProperty(@subscriber, "Status", @status)
SET @cid = CreateObject("ClientID")
SetObjectProperty(@cid, "ID", @BU_MID)
SetObjectProperty(@cid, "IDSpecified", "true")
SetObjectProperty(@subscriber, "Client", @cid)
SET @options = CreateObject("UpdateOptions")
SET @save = CreateObject("SaveOption")
SetObjectProperty(@save, "SaveAction", "UpdateAdd")
SetObjectProperty(@save, "PropertyName", "*")
AddObjectArrayItem(@options, "SaveOptions", @save)
SET @result = InvokeUpdate(@subscriber, @update_sub_status, @update_sub_errorcode, @options)
]%%
<!-- ========== 6. 購読取り消し実行ページ ========== -->
<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>配信停止完了</title>
<style>
body{margin:0;font-family:Helvetica,Arial,sans-serif;color:#222;background:#fff;}
.wrap{max-width:920px;margin:0 auto;padding:24px;}
.card{margin-top:18px;padding:22px;border:1px solid #eee;border-radius:12px;}
h1{margin:0 0 10px 0;font-size:22px;}
p{margin:0;font-size:14px;line-height:1.8;}
.btns{margin-top:16px;display:flex;gap:10px;flex-wrap:wrap;}
.btn{display:inline-block;padding:12px 16px;border-radius:8px;text-decoration:none;font-weight:bold;}
.btn-primary{background:#111;color:#fff;}
.btn-ghost{background:#eee;color:#111;}
.foot{margin-top:26px;padding-top:14px;border-top:1px solid #eee;font-size:12px;color:#666;text-align:center;}
</style>
</head>
<body>
<div class="wrap">
<div class="card">
<h1>配信停止手続きが完了しました</h1>
<p>
メールマガジンの配信を停止しました。<br>
ご利用ありがとうございました。
</p>
<div class="btns">
<a class="btn btn-primary" href="https://YOUR-SITE-DOMAIN/" target="_blank" rel="noopener">公式サイトへ</a>
<a class="btn btn-ghost" href="https://YOUR-DOMAIN/subscription-center" target="_blank" rel="noopener">配信設定を確認</a>
</div>
</div>
<div class="foot">
© Your Company. All rights reserved.
</div>
</div>
</body>
</html>(HTML 部分はそのままでも、自由にカスタマイズしても構いません)

エラーページを設定していない場合は、プレビューでエラーメッセージが出ますが、無視して公開してください。

メール側の設定
続いて、以下の AMPscript を HTML ブロックで保存します。
https://YOUR-DOMAIN/unsubscribe が実行ページの Cloudpages URL です
%%[
VAR @secretKey, @encSubKey, @token, @confirmURL
SET @secretKey = Lookup("SecretKey_DE", "Value", "Name", "UnsubscribeKey")
SET @encSubKey = EncryptSymmetric(
_subscriberkey,
"AES",
@secretKey,
@null,
"0000000000000000", /* 16 chars IV */
@null,
"00000000000000000000000000000000", /* 32 chars Salt */
@null
)
SET @token = URLEncode(@encSubKey)
SET @confirmURL = Concat("https://YOUR-DOMAIN/unsubscribe?token=", @token)
]%%<a href="%%=RedirectTo(@confirmURL)=%%" alias="Custom Unsubscribe Link">配信停止はこちら</a>
メール本文には、ContentBlockById で HTML ブロックを参照します。
%%=ContentBlockById(" ")=%%

これにより、「配信停止はこちら」というリンクが生成されます。

動作確認
メール送信を前提としているため、購読者キーは必ず存在しています。
実際にメールを送信してリンクをクリックすると、その購読者キーが 購読取り消し状態になることを確認できるはずです。

トークン付 URL の例:https://YOUR-DOMAIN/unsubscribe?token=B4NKbtFO39cxmo+9xzXT+G/22bKE5EAAgRfFcdcuFwA=


いかがでしたでしょうか。
今回ご紹介した構成では、リンクをクリックするとそのまま購読取り消しを実行していますが、実行ページの前に「確認ページ」を挟む構成にすることも可能です。
その場合は、暗号化された購読者キー(トークン)をクエリパラメータとして次のページへ引き継ぎ、2 ページ目で購読取り消し処理を実行してください。
また、トークンが存在しない、もしくは不正な場合に備えて、エラーページを用意すると、より安全でユーザーフレンドリーな実装になります。
構成の自由度は高いので、ぜひ色々なパターンを試してみてください。
今回は以上です。
