条件付きでレコード作成をSlackへ通知するApexとフロー
Incoming WebhookのURLを取得し、Queueableで通知を送るApexクラスを作成し、レコードトリガーフローから呼び出すところまでを説明します。
シナリオ
取引先レコードが作成されたとき、取引先名に「テスト」という文字列が含まれる場合だけ、Slackへ通知します。すべての作成を通知するわけではありません。条件を満たしたときだけ、という判定が必要です。
先に確かめること 標準のSlack連携で足りないか
SalesforceにはSlackと連携する標準機能があります。チャンネルとレコードを結び付けて、レコードの更新をSlackへ流すような使い方が用意されています。まずは、その標準機能で要件が満たせないかを確かめてください。
本記事で扱うのは、「取引先名に特定の文字列を含む場合だけ」のように、条件で絞り込んでから通知するケースです。ここまで細かい条件分岐は自作のApexとフローが必要になります。
Incoming Webhookを発行する
SlackのIncoming Webhookは、投稿先チャンネルが決まったURLに対してJSONをPOSTするだけでメッセージを送れる仕組みです。現在はSlack Appを作成したうえで、その機能として発行します。
Slack Appを作成する
Slackの管理画面でアプリを新規作成し、投稿先のワークスペースを選びます。
Incoming Webhooksを有効にする
アプリの設定で「Incoming Webhooks」機能をオンにします。
ワークスペースへWebhookを追加する
「Add New Webhook to Workspace」から投稿先チャンネルを選び、認可します。
発行されたURLを控える
チャンネルごとに1本のURLが発行されます。このURLを知っている人は誰でもそのチャンネルへ投稿できるため、扱いには注意します。
発行されるURLは次の形です。
https://hooks.slack.com/services/TXXXXXXXXXX/BXXXXXXXXXX/xxxxxxxxxxxxxxxxxxxxxxxx
実際にはチャンネルごとに異なる文字列が入ります。第三者に渡さないでください。
Webhook URLをApexに直書きしない
⚠️ Webhook URLはSlackに投稿できる鍵そのものです。Apexクラスの中に文字列リテラルで埋め込むと、そのクラスを見られるすべての人に渡ることになり、変更のたびにデプロイも必要になります。
コードに出さない置き場所として、次のような選択肢があります。
| 置き場所 | 向いている場面 |
|---|---|
| カスタムメタデータ型 | 値を環境ごとに変え、デプロイでも配布したい場合 |
| カスタム設定(階層型) | 管理者が画面から値を書き換えられるようにしたい場合 |
| 名前付き認証情報 | エンドポイントをコードから完全に切り離し、リモートサイト設定も省きたい場合 |
ここではカスタムメタデータ型を使います。SlackWebhook__mdt を作成し、Url__c(テキスト)に発行したURLを保存します。
通知用Apexクラスを作成する
Webhook URLはメタデータ型から読み込みます。呼び出し元にはInvocableVariableでメッセージとチャンネルを渡せるようにします。コールアウトはトリガー由来の同期処理から直接は行えないため、Queueableに包みます。
public with sharing class PublishToSlack { public class SlackRequest { @InvocableVariable(label='Slack Message' required=true) public String slackMessage; @InvocableVariable(label='Channel or User' required=true) public String channel; } @InvocableMethod(label='Publish to Slack' callout=true) public static void publish(List<SlackRequest> requests) { SlackWebhook__mdt setting = SlackWebhook__mdt.getInstance('Default'); String webhookUrl = setting.Url__c; for (SlackRequest r : requests) { JSONGenerator gen = JSON.createGenerator(true); gen.writeStartObject(); gen.writeStringField('text', r.slackMessage); gen.writeStringField('channel', r.channel); gen.writeStringField('username', 'Salesforce Bot'); gen.writeEndObject(); System.enqueueJob(new NotifySlackJob(webhookUrl, gen.getAsString())); } } }
フローから渡された内容をQueueableへ渡し、コールアウトを非同期で実行します。読み取りはメタデータ型のみで、DMLは行いません。
public class NotifySlackJob implements System.Queueable, Database.AllowsCallouts { private final String endpoint; private final String body; public NotifySlackJob(String endpoint, String body) { this.endpoint = endpoint; this.body = body; } public void execute(System.QueueableContext ctx) { HttpRequest req = new HttpRequest(); req.setEndpoint(endpoint); req.setMethod('POST'); req.setHeader('Content-Type', 'application/json'); req.setBody(body); Http http = new Http(); HttpResponse res = http.send(req); System.debug(LoggingLevel.INFO, 'Slack response: ' + res.getStatusCode()); } }
Queueableの中でHTTPのPOSTを実行します。Database.AllowsCalloutsが無いと実行時エラーになります。
@InvocableMethod は、フローから呼び出せるメソッドを1クラスにつき1つだけ指定するアノテーションです。callout 修飾子は、そのメソッドが外部システムへコールアウトすることを示します。外部への通信を伴うURLをリモートサイト設定へ登録する必要がありますが、名前付き認証情報を使う場合はリモートサイト設定の登録が不要になります。
レコードトリガーフローを作成する
⚠️ この記事を最初に書いた当時は、プロセスビルダーで組む前提でした。プロセスビルダーとワークフロールールはすでにサポートが終了しており、新規の自動化はフローで作成します。
フローの種類を選ぶ
Flow Builderで新規作成し、「レコードトリガーフロー」を選びます。対象オブジェクトは取引先、条件は「レコードが作成されたとき」にします。
条件を設定する
「フローの実行条件」に、取引先名に「テスト」を含む場合という条件式を追加します。
Apexアクションを配置する
要素を追加し、Apexアクションから「Publish to Slack」を選びます。
入力値を設定する
Slack Messageに通知文、Channelに投稿先チャンネル名を設定します。値はレコードの項目を式で組み立てられます。
保存して有効化する
フローに名前を付けて保存し、有効化します。
動作確認
取引先名を「テスト顧客」としたレコードを新規作成し、保存します。フローの実行条件に一致するため、Apexアクションが呼び出され、Queueableのジョブがコールアウトを実行します。Slackの投稿先チャンネルに、設定したメッセージが届いていれば成功です。届かない場合は、Setup の「フローの実行結果」と、Apexジョブの実行履歴(非同期Apexジョブ)を確認します。
ここで間違えやすい
| 間違い | 何が起きるか |
|---|---|
| Webhook URLをApexへ直書きする | 動きはしますが、値の変更にデプロイが要り、コードを見た人にURLが渡ります |
Queueableクラスに Database.AllowsCallouts を付けない | 実行時に例外になります |
| プロセスビルダーで新規に組もうとする | サポートが終了しているため避けます。レコードトリガーフローを使います |
確認した環境
- 2026年9月 / Salesforce Summer '26(API バージョン 67.0)時点の公式ドキュメントで確認しています
- Slack側の手順は
docs.slack.dev(api.slack.comからのリダイレクト先)の公式ドキュメントで確認しています
まとめ
- Webhook URLはApexへ直書きせず、カスタムメタデータ型・カスタム設定・名前付き認証情報のいずれかに置きます
- コールアウトは
@future(callout=true)かQueueableで非同期に行います。トリガー由来の同期処理から直接は呼べません - プロセスビルダーとワークフロールールはサポートが終了しています。新規の自動化はレコードトリガーフロー+
@InvocableMethodで組みます - 条件で絞り込む通知は自作が要りますが、まず標準のSlack連携で足りないかを確かめる価値があります
参考:当時の画面
記事を最初に書いた当時の画面です。いまの手順と違うところは、各画像の説明に書いています。
Salesforceの導入・運用についてご相談ください
導入前の検討から、お使いの環境の改修・運用、AIとの連携まで承ります。状況を伺ったうえで、進め方をご提案します。