【第545回】 Marketing Cloud Next : メールプレビュー機能のカスタムタブ
Marketing Cloud Next Growth & Advanced Editions では、メールコンテンツにおける「プレビューとテスト」の画面に、Lightning Web コンポーネント(Salesforce の画面に画面・ボタン・表・グラフなどを作るための仕組み)を使用した 独自のタブ を追加できます。
そこで、今回は Agentforce Vibes IDE(ブラウザ版 VS Code)を使って、次の 3 項目を確認する「Content Check」タブを作成します。
メール件名の文字数
プリヘッダーの未入力と文字数
プリファレンスセンターへのリンクの有無
完成すると、Marketing Cloud Nextのプレビュー画面に次のようなタブが追加されます。
Preview|Test|Content Check「Content Check」タブを開くと、現在プレビューしているメールの内容を基に、次のようなチェック結果が表示されます。

※ Agentforce Vibes IDE は、SDO、Developer Edition または 各種エディションの Sandbox でのみ利用ができます。一般的な本番組織では Agentforce Vibes IDE を利用することはできません。
設定手順
1. Agentforce Vibes IDE を有効化する
まず Salesforce の設定画面から Agentforce Vibes IDE を起動します。
1.Agentforce Vibes を開く
Salesforce へログインし、画面右上の歯車アイコンから「設定」を開き、「Agentforce Vibes」を選択します。

2.利用規約に同意する
初回起動時には Agentforce Vibes IDE の利用規約 が表示されます。
「Accept」をクリックすると、Agentforce Vibes IDE を利用できるようになります。なお、この利用規約は Agentforce Vibes IDE だけでなく、DevOps Center や DX Inspector など、Salesforce DXツール共通の利用規約となっています。

ロードされるまで数分待ちます。

今回の実装は、Agentforce の支援なしで作ります。なぜなら、以下の赤枠の Agentforce 機能を有効化できない環境も多いためです。有効化できる場合は、利用して作成してください。

この「Enable Agentforce」をクリックすると、Agentforce Vibes の AI 開発アシスタントが有効になります。これにより、AI によるコード生成やレビュー機能を利用できるようになります。
3.Agentforce Vibes IDE を起動する
ブラウザ上に Visual Studio Code とよく似た開発画面が開きます。

Tips:初回起動時に画面右下に「Apex Language Server Extension couldn't create connection to server」などのエラーが表示される場合があります。その場合は、Ctrl + Shift + P を押して Developer: Reload Window を実行すると解消することがあります。
2. Salesforce プロジェクトを作成する
次に、LWC を保存する Salesforce プロジェクトを作成します。
1.コマンドパレットを開く
Agentforce Vibes IDE 上で、次のキーを押します。
Windows:
Ctrl + Shift + PMac:
Command + Shift + P画面上部にコマンドパレットが表示されます。

2.Salesforce プロジェクトを作成する
コマンドパレットに、次の文字を入力します。
SFDX: Create Project
プロジェクトの種類は、標準のプロジェクトを選択します。

プロジェクト名は、例えば次のようにします。
MarketingCloudNextPreviewExtension
保存場所を選択すると、Salesforce プロジェクトが作成されます。

Tips:Agentforce Vibes IDE を Salesforce 組織の設定画面から起動している場合、自動的ににその対象組織を認識した状態で利用できます。
※なお、画面を離れてしまい、再度 MarketingCloudNextPreviewExtension のプロジェクトに戻りたい場合は、Open File か Recent から戻れます。

(参考)Agentforce に LWC を作ってもらう
もし、AI に支援してもらいながら作成する場合は、Agentforce Vibes の入力欄に、以下のようなプロンプトを入力して送信します。
Marketing Cloud Next の Preview and Test モーダルに追加する
Lightning Web Component を作成してください。
コンポーネント名は contentCheckTab としてください。
要件は次のとおりです。
1. @api previewData で Marketing Cloud Next からデータを受け取る
2. previewData.emailSubject をメール件名として表示する
3. メール件名が未入力の場合はエラーを表示する
4. メール件名の文字数を表示する
5. メール件名が 50 文字を超えた場合は警告を表示する
6. previewData.emailPreheader をプリヘッダーとして表示する
7. プリヘッダーが未入力の場合はエラーを表示する
8. プリヘッダーの文字数を表示する
9. プリヘッダーが 100 文字を超えた場合は警告を表示する
10. previewData.content からプリファレンスセンターへのリンクが
含まれているか確認する
11. リンクが見つからない場合はエラーを表示する
12. 最後にPASSまたは修正が必要という総合判定を表示する
13. Salesforce Lightning Design System のクラスを使用する
14. Apex は使用しない
15. 外部 API は使用しない
16. lightning__dynamicComponent capability を設定する
17. null または undefined が渡されても JavaScript エラーにならないようにする
18. 作成するファイルは次の 3 つとする
contentCheckTab.html
contentCheckTab.js
contentCheckTab.js-meta.xml
作成前に実装方針を説明し、その後ファイルを作成してください。これにより Agentforce が実装内容を確認し、必要なファイルを作成します。
3. 手動で作成されたファイルを作成する
今回は手動でフォルダやファイルを作成していきますので、以下のディレクトリを lwc 配下に作成してください。
force-app/
└── main/
└── default/
└── lwc/
└── contentCheckTab/(<--- フォルダ)
├── contentCheckTab.html(<--- HTMLファイル)
├── contentCheckTab.js(<--- JSファイル)
└── contentCheckTab.js-meta.xml(<--- XMLファイル)
各ファイルのテンプレートです。
contentCheckTab.html
<template>
<div class="slds-p-around_medium">
<div class="slds-text-heading_medium slds-m-bottom_medium">
Content Check
</div>
<template if:true={hasPreviewData}>
<section class="slds-box slds-m-bottom_medium">
<h2 class="slds-text-heading_small">件名</h2>
<p class="slds-m-top_x-small">{subjectDisplay}</p>
<p>{subjectLength}文字</p>
<p class={subjectStatusClass}>{subjectStatus}</p>
</section>
<section class="slds-box slds-m-bottom_medium">
<h2 class="slds-text-heading_small">プリヘッダー</h2>
<p class="slds-m-top_x-small">{preheaderDisplay}</p>
<p>{preheaderLength}文字</p>
<p class={preheaderStatusClass}>{preheaderStatus}</p>
</section>
<section class="slds-box slds-m-bottom_medium">
<h2 class="slds-text-heading_small">
プリファレンスセンター
</h2>
<p class={preferenceCenterStatusClass}>
{preferenceCenterStatus}
</p>
</section>
<section class="slds-box">
<h2 class="slds-text-heading_small">総合判定</h2>
<p class={overallStatusClass}>{overallStatus}</p>
</section>
</template>
<template if:false={hasPreviewData}>
<div class="slds-text-color_error">
プレビューデータを取得できませんでした。
</div>
</template>
</div>
</template>
contentCheckTab.js
import { LightningElement, api } from "lwc";
const SUBJECT_MAX_LENGTH = 50;
const PREHEADER_MAX_LENGTH = 100;
export default class ContentCheckTab extends LightningElement {
@api previewData;
get hasPreviewData() {
return this.previewData != null;
}
get subject() {
return this.previewData?.emailSubject?.trim() || "";
}
get preheader() {
return this.previewData?.emailPreheader?.trim() || "";
}
get content() {
return this.previewData?.content || "";
}
get subjectDisplay() {
return this.subject || "未入力";
}
get preheaderDisplay() {
return this.preheader || "未入力";
}
get subjectLength() {
return Array.from(this.subject).length;
}
get preheaderLength() {
return Array.from(this.preheader).length;
}
get isSubjectValid() {
return (
this.subjectLength > 0 &&
this.subjectLength <= SUBJECT_MAX_LENGTH
);
}
get isPreheaderValid() {
return (
this.preheaderLength > 0 &&
this.preheaderLength <= PREHEADER_MAX_LENGTH
);
}
get hasPreferenceCenter() {
const content = this.content.toLowerCase();
const preferenceCenterPatterns = [
"preference",
"subscription",
"unsubscribe",
"manage preferences"
];
return preferenceCenterPatterns.some((pattern) =>
content.includes(pattern)
);
}
get subjectStatus() {
if (this.subjectLength === 0) {
return "件名が未入力です。";
}
if (this.subjectLength > SUBJECT_MAX_LENGTH) {
return `件名が${SUBJECT_MAX_LENGTH}文字を超えています。`;
}
return "問題ありません。";
}
get preheaderStatus() {
if (this.preheaderLength === 0) {
return "プリヘッダーが未入力です。";
}
if (this.preheaderLength > PREHEADER_MAX_LENGTH) {
return `プリヘッダーが${PREHEADER_MAX_LENGTH}文字を超えています。`;
}
return "問題ありません。";
}
get preferenceCenterStatus() {
return this.hasPreferenceCenter
? "プリファレンスセンターへのリンク候補が見つかりました。"
: "プリファレンスセンターへのリンクが見つかりません。";
}
get isAllValid() {
return (
this.isSubjectValid &&
this.isPreheaderValid &&
this.hasPreferenceCenter
);
}
get overallStatus() {
return this.isAllValid ? "PASS" : "修正が必要です";
}
get subjectStatusClass() {
return this.isSubjectValid
? "slds-text-color_success"
: "slds-text-color_error";
}
get preheaderStatusClass() {
return this.isPreheaderValid
? "slds-text-color_success"
: "slds-text-color_error";
}
get preferenceCenterStatusClass() {
return this.hasPreferenceCenter
? "slds-text-color_success"
: "slds-text-color_error";
}
get overallStatusClass() {
return this.isAllValid
? "slds-text-heading_medium slds-text-color_success"
: "slds-text-heading_medium slds-text-color_error";
}
}
contentCheckTab.js-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle
xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>66.0</apiVersion>
<isExposed>true</isExposed>
<capabilities>
<capability>lightning__dynamicComponent</capability>
</capabilities>
</LightningComponentBundle>
4. プリファレンスセンターを調整する
プリファレンスセンターの URL や識別文字列は、組織やメールテンプレートの構成によって異なります。
今回のサンプルでは、メール本文の中(文字列内でも URL 内でも)に
preference
subscription
unsubscribe
manage preferences
のどれか 1 つでも含まれていれば「プリファレンスセンターあり」との判定になります。
get hasPreferenceCenter() {
const content = this.content.toLowerCase();
const preferenceCenterPatterns = [
"preference",
"subscription",
"unsubscribe",
"manage preferences"
];
return preferenceCenterPatterns.some((pattern) =>
content.includes(pattern)
);
}実際に使用しているプリファレンスセンターの URL が分かっている場合は、そのドメインや URL の一部を条件に加えた方が確実です。
例えば、実際の URL に次の文字列が必ず含まれる場合を考えます。
preferences.example.comその場合は、判定条件へ次の値を追加します。
const preferenceCenterPatterns = [
"preferences.example.com",
"manage preferences"
];5. LWC を組織へデプロイする
内容を確認したら、作成した LWC を組織へデプロイします。
ファイル一覧からデプロイする
ファイル一覧で contentCheckTab フォルダ右クリックし、表示されたメニューから、組織へソースをデプロイする以下を選択します。
SFDX: Deploy This Source to Org
6. デプロイされた LWC の ID を確認する
LWC をデプロイしただけでは、Marketing Cloud Next のプレビュー画面には表示されません。次に、デプロイした contentCheckTab の ID を確認したいので、Salesforce の設定画面から「開発者コンソール」を開きます。

開発者コンソールで「Query Editor」を選択し、「Use Tooling API」にチェックを入れます。

今回取得したい LightningComponentBundle は、Contact や Case のような通常のデータオブジェクトではなく、デプロイされた LWC の定義情報です。そのため、Use Tooling API にチェックを入れる必要があります。
次のクエリを実行します。
SELECT Id, DeveloperName, IsExposed, NamespacePrefix
FROM LightningComponentBundle
WHERE DeveloperName = 'contentCheckTab'結果に表示された 18 桁の Id をメモします。

この ID は、次の UiPreviewMessageTabDef 登録時に使用します。
7. UiPreviewMessageTabDef を登録する
UiPreviewMessageTabDef は、Marketing Cloud Next の「プレビューとテスト」モーダルへ、どの LWC をどのタブ名で表示するかを登録するためのメタデータです。
開発者コンソールの Query Editor で、次のクエリを実行します。
SELECT Id, MasterLabel, DeveloperName, TabName, IsActive, SupportedChannel, LightningComponentDefId
FROM UiPreviewMessageTabDef
このクエリの結果は 0 件となりますが、これは登録済みのカスタムタブが 0 件なので正常です。

次に、「Insert Row」を 1 度だけクリックすると、新しい行が追加されると思います。

各項目には、例えば次のような値を設定します。
Id:自動採番のため入力できません
MasterLabel:Content Check
DeveloperName:ContentCheck
TabName:Content Check
IsActive:true
SupportedChannel:Email
LightningComponentDefId:先ほどコピーした contentCheckTab の ID

入力後、「Save Rows」をクリックします。


ここで、IsActive を true にすると、Marketing Cloud Nextの プレビュー画面へタブが表示されます。
8. Marketing Cloud Next で動作確認する
Marketing Cloud Next でメールコンテンツに移動し、「プレビューとテスト」を開きます。

標準のプレビュータブとテストタブの横に、次のタブが表示されます。
Content Check
タブを開いて、チェック結果を確認します。

いかがでしたでしょうか。
今回は、Agentforce Vibes IDE を開発環境として利用し、Marketing Cloud Next の「プレビューとテスト」画面へ独自の「Content Check」タブを追加してみました。
一見すると小さなサンプルですが、この機能を利用すると、送信前の確認を自社の運用ルールに合わせて自由に拡張できます。
例えば、
ブランドガイドラインのチェック
差し込み項目の未設定チェック
リンク切れチェック
必須コンテンツの確認
独自ルールによる品質チェック
など、さまざまな送信前チェックツールをプレビュー画面へ追加することが可能です。
Marketing Cloud Next のプレビュー画面を自社向けにカスタマイズできること自体、まだあまり知られていない機能です。
ぜひ皆さんの環境でも、独自のチェックタブ作成にチャレンジしてみてください。
今回は以上です。
