テンプレート、ルール、Webhook
`templates`、`rules`、`webhooks` のすべてのコマンド。スラッグを指定して送る保存済みの本文、届いたメールを振り分けるルール、自分のサーバー向けの署名付きイベントです。
3 つの名前空間
この 3 つの名前空間を使うと、誰も見ていなくてもメールボックスが動き続けます。templates は何度も送る本文を保存し、rules は届いたメールを振り分け、webhooks は何が起きたかを自分のサーバーに知らせます。各コマンドは SDK のメソッドをケバブケースの名前にしたものなので、webhooks.rotateSecret は openemail webhooks rotate-secret になり、他のリソースコマンドと同じように引数とフラグを読み取ります。
| 名前空間 | 別名 | 読み取りに必要 | 変更に必要 |
|---|---|---|---|
| templates | template | templates:read | templates:write。send には emails:send も必要 |
| rules | rule | rules:read(test を含む) | rules:write |
| webhooks | webhook | webhooks:read | webhooks:write(test と replay-delivery を含む) |
このページでは、すべてのコマンドと、スクリプトに組み込む前に知っておくべきことをまとめています。すべての引数とフラグを、その型、必要なスコープ、エンドポイント、返す内容とともに見るには、openemail <namespace> <verb> --help を実行してください。--json を付けると、同じページを JSON で得られます。
openemail templates --helpopenemail rules create --helpopenemail webhooks replay-delivery --help --jsonテンプレート
一度保存して何度も送る本文で、バージョン、プレビュー、型付きの props を持ちます。<id-or-slug> を受け取るコマンドはすべて、tpl_ の ID かスラッグを受け付けます。テンプレートの名前を変えてもスラッグは変わらないので、スクリプトではスラッグを固定してください。
| コマンド | 機能 |
|---|---|
| openemail templates list | テンプレートを最近更新した順に一覧表示します。--status で下書き、有効、アーカイブ済みのいずれかに絞り、--search で名前、スラッグ、件名を照合し、--sort で並び順を選びます |
| openemail templates get <id-or-slug> | テンプレートを、本文を含むヘッドバージョン全体とともに読みます |
| openemail templates create --name <value> | テンプレートとその最初のバージョンを作成します。--publish を渡さない限り下書きのままで、--starter を使うとスターターデザインから始めます |
| openemail templates update <id-or-slug> | 名前、スラッグ、説明、ステータス、または下書きの本文を編集します。公開するまで、送信には公開済みのバージョンが使われ続けます |
| openemail templates duplicate <id-or-slug> | ヘッドバージョンを新しいテンプレートにコピーします。新しいテンプレートは下書きとして始まります |
| openemail templates replace-content <id-or-slug> | 本文をスターターのもの(--starter)か別のテンプレートのもの(--from-template-id)に差し替えます。確認を求めます |
| openemail templates delete <id-or-slug> | テンプレートとすべてのバージョンを削除します。確認を求めます |
| openemail templates list-versions <id-or-slug> | バージョンを新しい順に、本文なしで一覧表示します |
| openemail templates get-version <id-or-slug> <version> | 下書きに触れずに、1 つのバージョンを本文とともに読みます |
| openemail templates publish <id-or-slug> | 下書きを公開し、送信でそれが使われるようにします。すでに公開中のヘッドを公開しても何も変わりません |
| openemail templates restore-version <id-or-slug> <version> | 古いバージョンの本文を下書きとして戻します。確認を求めます |
| openemail templates delete-version <id-or-slug> <version> | 1 つのバージョンを削除します。公開中のバージョン、ヘッド、唯一のバージョンは拒否されます。確認を求めます |
| openemail templates list-starters | 組み込みのスターターデザインを一覧表示します |
| openemail templates get-starter <slug> | 1 つのスターターを、ブロックツリーとレンダリングされたプレビューを含めて完全に読みます |
| openemail templates list-fonts | テンプレートが読み込めるウェブフォントを一覧表示します |
| openemail templates render | どこにも保存されていない本文を、--html または --document からレンダリングします |
| openemail templates preview <id-or-slug> | 保存済みのテンプレートを、下書きも含めて --props と --slots でレンダリングします。送信はしません |
| openemail templates get-analytics <id-or-slug> | ある期間の送信、開封、クリックを、日別、送信元別、バージョン別に表示します |
| openemail templates list-sends <id-or-slug> | テンプレートが送った個々のメッセージを、新しい順に 1 ページずつ表示します |
| openemail templates send <id-or-slug> --from <value> --to <a,b> | 公開済みのバージョン、または --template-version で固定したバージョンからレンダリングしたメールを送信します |
テンプレートには、未公開の編集がある間は下書きとなるヘッドバージョンと、--template-version なしの送信で使われる公開済みバージョンがあります。--publish なしの create、update による本文の編集、replace-content、restore-version はすべて下書きに書き込むので、publish するまで受信者に新しい内容は届きません。
- アーカイブ済みのテンプレートは
template_archivedで送信を拒否します。publishで再び有効になります。 - ワークスペースに置けるテンプレートは、アーカイブ済みのものを含めて最大 200 個なので、空きを作るには削除するしかありません。
- 予約済みまたはキュー待ちの一斉配信がまだそのテンプレートを指定している間、
deleteはtemplate_in_useで拒否されます。
ルール
届いたメールに対して、rules list が示す順に評価される条件とアクションです。ルールが作用するのは、有効になっている間に届いたメールだけです。メールボックスにすでにあるメールにルールを適用するコマンドはなく、何が該当するかを確認するには rules test を使います。ルールの ID は rul_ で始まります。
| コマンド | 機能 |
|---|---|
| openemail rules list | ルールを実行される順に一覧表示します。--enabled または --no-enabled でどちらかに絞ります |
| openemail rules get <id> | 1 つのルールを matchCount と lastMatchedAt とともに読みます |
| openemail rules create --name <value> --conditions <json|@file|-> --actions <json|@file|-> | 順序の最後にルールを作成します。--no-enabled を渡さない限り有効です |
| openemail rules update <id> | ルールを変更します。--conditions と --actions はリスト全体を置き換え、--position はこのルールだけを移動します |
| openemail rules delete <id> | ルールを削除します。すでに行った処理は list-runs に残ります。確認を求めます |
| openemail rules reorder <rule-ids...> | すべてのルールの順序を一度に設定します。各ルールをちょうど 1 回ずつ指定します |
| openemail rules test <id> | メールボックスにすでにあるメールに対してルールをドライランします。何も変更せず、無効なルールでも使えます |
| openemail rules list-runs | ルールが届いたメールに実際に何をしたかを新しい順に表示します。--rule-id と --thread-id で絞り込めます |
--conditions は { field, op, value } オブジェクトのリストで、--match all または --match any で結び付けられます。value は常に文字列で、negate: true を付けるとその条件が反転します。--actions は { type, value } オブジェクトのリストで、順番に適用されます。ルールには 1 から 20 個の条件と 1 から 10 個のアクションを指定でき、メールボックスに置けるルールは最大 100 個です。
- 条件のフィールド:
from、from_domain、envelope_from、to、cc、bcc、recipient、reply_to、delivered_to、subject、body、header、list_id、attachment_name、attachment_type、has_attachment、attachment_size、message_size、spam、hour、weekday。 - 演算子:
matches、contains、equals、starts_with、ends_with、gt、lt。gtとltは数値のフィールドでのみ使え、has_attachmentとspamはtrueかfalseを指定したequalsだけを受け付けます。 - アクションの種類:
label、remove_label、archive、mark_read、star、spam、trash、forward、reply、block_sender、reject。labelとremove_labelはUSER_RECEIPTSのようなラベル ID を、forwardはアドレスを、replyはテンプレートの ID かスラッグを受け取ります。 from_domainはサブドメインにも一致し、hourとweekdayは UTC で読み取られ、日曜日は0です。rejectアクションを持つルールはenvelope_fromも判定しなければならず、そうでなければreject_needs_envelopeで拒否されます。
Webhook
署名付きのメールボックスイベントを受け取る、自分のサーバー上のエンドポイントです。署名シークレット、配信ログ、すべての変更の監査ログがあります。エンドポイントの ID は whe_ で、配信の ID は whd_ で始まります。
| コマンド | 機能 |
|---|---|
| openemail webhooks list | ワークスペースのエンドポイントを新しい順に、正常性とともに一覧表示します |
| openemail webhooks get <id> | 1 つのエンドポイントを読みます。署名シークレットは読み取りには決して含まれません |
| openemail webhooks create --url <value> | HTTPS のエンドポイントを登録します。署名シークレットが表示され、それを見られるのはこのときだけです |
| openemail webhooks update <id> | URL、イベント、許可リスト、有効かどうかを変更します。各リストは保存されているものを置き換えます |
| openemail webhooks delete <id> | エンドポイントとその配信ログを削除します。確認を求めます |
| openemail webhooks rotate-secret <id> | 新しい署名シークレットを発行します。古いものはすぐに使えなくなります。確認を求めます |
| openemail webhooks test <id> | 署名付きの合成 email.sent イベントを送信し、配信の結果を報告します |
| openemail webhooks list-deliveries <id> | 1 つのエンドポイントへの配信の試行を新しい順に表示します。--status、--since、--until で絞り込めます |
| openemail webhooks get-delivery <id> <delivery-id> | 1 回の試行の全体です。送った本文、サーバーの応答、そのイベントのすべての試行、そして再送が受け付けられるかどうか |
| openemail webhooks replay-delivery <id> <delivery-id> | 保存された 1 つのイベントを、今すぐもう一度エンドポイントに送ります |
| openemail webhooks list-workspace-deliveries | すべてのエンドポイント、または --endpoint-ids で指定したエンドポイントへの配信の試行 |
| openemail webhooks list-activity <id> | 1 つのエンドポイントの監査ログです。誰が作成、変更、テスト、再送、削除したか |
| openemail webhooks list-workspace-activity | 削除されたものを含む、すべてのエンドポイントの監査ログ |
--event-types を省略すると、エンドポイントは既定のセット、つまり email.replied 以外の email.* イベントを受け取ります。email.replied、domain.* イベント、suppression.* イベントは、指定したときだけ届きます。--address-allowlist と --domain-allowlist は、API キーを絞り込むのと同じように、エンドポイントを一部のアドレスやドメインに絞り込みます。
- ワークスペースに置けるエンドポイントは、サポートが上限を引き上げていない限り 10 個です。
- 100 回続けて配信に失敗したエンドポイントはサーバーによってオフにされ、
webhooks update <id> --enabledで元に戻せます。 - ブラウザでのサインインでは、
get-deliveryで配信を読めるのはワークスペースのオーナーだけです。それ以外の人はowner_onlyと終了コード4になります。
テンプレートを確認してから公開する
templates preview は、下書きも含め、同じ値で送信した場合とまったく同じものをレンダリングし、templates:read だけで使えるので、読み取り専用のキーでも実行できます。必須の prop がない場合、send なら拒否するところを警告として報告するので、警告が 1 つでもあればビルドを失敗させてください。すでに公開中のヘッドを公開しても何も変わらないので、publish はデプロイのたびに実行しても安全です。
draft=$(openemail templates get order-shipped --json | jq .latestVersion)openemail templates preview order-shipped --template-version "$draft" \ --props '{"orderId":"AC-4192","customer":"Ada"}' --json | jq -e '.warnings == []'openemail templates publish order-shippedテンプレートから送信する
バージョンを固定して、明日公開される書き直しでこのコードが送る内容が変わらないようにし、送信のきっかけとなったものから取った冪等キーを渡して、応答が失われた後の再試行で 2 通目を送る代わりに最初のメッセージが再生されるようにします。--dry-run はメソッド、URL、認証情報を伏せたヘッダー、本文を表示し、何も送らずに終了コード 0 で終了します。送信するには --dry-run を外してもう一度実行します。
openemail templates send order-shipped \ --from 'Acme <[email protected]>' \ --to [email protected] \ --template-version 5 \ --props '{"orderId":"AC-4192","customer":"Ada"}' \ --idempotency-key order-shipped:AC-4192 \ --dry-run実行前にルールをテストする
ルールをオフの状態で作成し、最近のメールに対してドライランして、意図したものを捕まえるようになったらオンにします。ブラウザでサインインしている場合、rules create と rules update は確認コードを求めますが、スクリプトでは入力できないので、先に openemail verify を実行してください。その後 60 分間、そのプロファイルは確認なしでこれらを実行します。
[ { "field": "from_domain", "op": "equals", "value": "stripe.com" }, { "field": "has_attachment", "op": "equals", "value": "true" }][ { "type": "label", "value": "USER_RECEIPTS" }, { "type": "archive" }]openemail verifyrule=$(openemail rules create --name 'Stripe receipts' \ --conditions @conditions.json --actions @actions.json --no-enabled --json | jq -r .id)openemail rules test "$rule" --days 30 --limit 100openemail rules update "$rule" --enabledrules test の一致結果より先に警告を読んでください。field_unevaluable は、保存されたメールにもう含まれていないものを条件が読んでいるためテストで判断できなかったことを、forward_unverified は転送先がここでホストされていないことを意味します。wouldApply はルールが宣言している内容を一覧表示します。確認を済ませていないアドレスへの転送は、実際のメールが届いたときにはやはり失敗します。
ルールを先頭にし、メッセージが移動した理由を確認する
rules reorder はメールボックスのすべてのルールをちょうど 1 回ずつ受け取ります。抜けているルールや 2 回指定されたルールがあると拒否され、何も移動しません。rules list は実行順に ID を返すので、先頭にしたいルールを残りの前に置いてください。
first=rul_4f1c9a2b7d3e8f6a0b5c1d2eopenemail rules reorder "$first" $(openemail rules list --all --ndjson \ | jq -r --arg first "$first" 'select(.id != $first) | .id')openemail rules list-runs --thread-id CAHk7pQ2x9LmZ4 --json | jq '.items[] | {ruleName, actions, failures}'list-runs は実際に起きたことの記録です。各行は 1 つのルールが 1 通のメッセージに一致したことを表し、実行されたアクションと、failures にはメールボックスが実行しなかったもの(その日すでに返信した送信者への返信など)が含まれます。各行にはその時点のルール名が残るので、その後削除したルールでも --rule-id が使えます。
Webhook を登録して動作を確かめる
webhooks create は署名シークレットを 1 回だけ表示し、以降のコマンドで再び表示されることはありません。--json を付けると stdout の JSON に含まれ、保存を促すメッセージは stderr に出るので、出力はそのまま解析できます。webhooks test は、エンドポイントが何を購読していても署名付きの合成 email.sent イベントを送り、メールは送信されません。
openemail verifyopenemail webhooks create --url https://hooks.acme.com/openemail \ --event-types email.received,email.bounced,email.complained \ --description 'Support desk sync' --json > endpoint.jsonjq -r .secret endpoint.jsonopenemail webhooks test "$(jq -r .id endpoint.json)" --json | jq .deliveryrm endpoint.jsonファイルを削除する前に、シークレットをシークレットストアに入れてください。test はサーバーが失敗しても終了コード 0 で終了するので、delivery.status を読んでください。2xx の応答なら delivered、それ以外ならリダイレクトも含めて failed です。リダイレクトは決してたどらないからです。responseCode が null の場合は、応答がまったく届かなかったことを意味します。
失敗した配信を見つけて再送する
自分の側で障害が起きた後、すべてのエンドポイントで失敗したものを一覧にし、再送が受け付けられることを確認して、イベントをもう一度送ります。再送は同じイベント ID を持つので、処理済みの ID を捨てる受信側は、それを既知のイベントとして扱います。
openemail webhooks list-workspace-deliveries --status failed --since 2026-09-26T00:00:00Z --all --ndjson \ | jq -r '[.endpointId, .id, .eventType, (.responseCode // "no answer")] | @tsv'openemail webhooks get-delivery whe_3f9c2a7b1e4d8f60a5c7b92d whd_8c1e4a7f2b9d3e6a0c5f1b28 --json | jq .replayRefusalopenemail webhooks replay-delivery whe_3f9c2a7b1e4d8f60a5c7b92d whd_8c1e4a7f2b9d3e6a0c5f1b28--sinceと--untilは ISO 8601 の日時を受け取ります。nextAttemptAtに時刻が入っている失敗の行には、まだ自動の再試行が予定されています。replayRefusalは、再送が行われる場合はnullで、そうでなければ拒否される理由を示します。たとえばエンドポイントがオフの間はwebhook_disabledです。- 再送は 1 イベントずつ行います。失敗したすべての配信をまとめて再送するコマンドはありません。
確認コード
ブラウザでサインインしている場合、このうち 4 つのコマンドは、Web アプリと同じように、何かを変更する前に確認コードを求めます。rules create、rules update、webhooks create、webhooks update です。API キーが求められることはありません。このページの他のコマンドは、削除や webhooks rotate-secret も含め、コードなしで実行されます。
- ターミナルでは、CLI が 6 桁のコードをメールで送るか、2 段階サインインが有効なら認証アプリのコードを求め、その後コマンドを 1 回実行します。
--jsonや--no-inputを付けたとき、CI の中、またはターミナルがないときの無人実行では、誰もコードを入力できないので、コマンドは終了コード4で停止し、何も変更しません。先にopenemail verifyを実行すれば、そのプロファイルは 60 分間コードが不要になります。--yesは削除を確認しますが、コードを省略することはありません。
確認とドライラン
ここにある 7 つのコマンドは何かを削除または上書きするため、まず確認を求めます。templates delete、templates delete-version、templates replace-content、templates restore-version、rules delete、webhooks delete、webhooks rotate-secret です。無人実行では、--yes を渡さない限り、どれも終了コード 2 で停止します。
$ openemail webhooks delete whe_3f9c2a7b1e4d8f60a5c7b92d --no-input✗ Refusing to run unattended. Pass --yes to confirm.$ openemail webhooks delete whe_3f9c2a7b1e4d8f60a5c7b92d --yes--dry-run は何かを変更する最初のリクエストを表示し、送信も確認もせずに終了コード 0 で終了します。--json を付けると 1 つの { dryRun, request } ドキュメントを出力します。rules test、templates render、templates preview は何も変更しませんが、POST リクエストなので、ドライランでは実行せずに表示します。
ページング
templates list、templates list-versions、rules list、rules list-runs、そしてすべてのwebhooks list…コマンドは 1 ページずつ読みます。--limitで最大 100 行まで指定しない限り 25 行です。ターミナルには次のページのために渡す--cursorが表示されます。--allはすべてのページを読み、--max <n>はその行数で停止し、--ndjsonは 1 行に 1 つの JSON オブジェクトを出力します。--jsonを付けると、--allの場合も含めて、リストは 1 つの{ items, hasMore, nextCursor }ドキュメントを出力します。- カーソルは、それを受け取ったときと同じ絞り込み条件と並び順とともに渡してください。それ以外は
invalid_cursorとして終了コード7で拒否されます。 - 一方、
templates list-sendsは--pageと--page-sizeを使ってページ番号でページングし、totalを報告し、--allはありません。メールが送信されている間はページ番号がずれるので、深くページをたどるより--daysや--minutesで期間を絞ってください。 templates list-startersとtemplates list-fontsはカタログ全体を一度に返し、rules reorderはすべてのルールを新しい順序の単純なリストとして返します。- メールボックスに置けるルールは最大 100 個なので、
rules list --limit 100は常にすべてのルールを 1 ページで返します。
見直す価値のあるフラグ
--template-versionは本文のフィールドversionで、--versionが CLI のバージョンを表示するため名前を変えています。get-version、restore-version、delete-versionの<version>引数はバージョン番号で、tplv_の ID ではありません。--conditions、--actions、--document、--slots、--propsなどの JSON フラグは、JSON をインラインで、@pathでファイルから、または-で stdin から受け取ります。--dataは本文全体を同じ方法で受け取り、併せて渡したフラグは対応するキーを上書きします。--htmlはファイルではなくマークアップそのものを受け取るので、--html @page.htmlは@page.htmlという文字列を送ります。--html "$(cat page.html)"を渡すか、--dataに渡すファイルにhtmlを入れてください。rules update --conditionsと--actionsはリスト全体を置き換え、webhooks update --event-types、--address-allowlist、--domain-allowlistも同様です。現在の値を読み、変更し、すべてを送ってください。- 空の
--event-typesは使い方のエラーです。エンドポイントを既定のセットに戻すには--data '{"eventTypes":[]}'を送り、配信を止めるには--no-enabledを渡します。 templates update、replace-content、restore-versionの--expected-versionは、読み取ったヘッドバージョンを受け取ります。その後に他の誰かがヘッドを進めていた場合、コマンドは終了コード6とversion_conflictで停止し、何も書き込みません。rules update <id> --no-enabledはルールをオフにしつつ順序上の位置を保ちます。ルールを削除せずに一時停止するにはこの方法を使います。