ナレッジベース
テンプレート
一度書いた本文をバージョン管理し、何度も送信する。コンポーザーから、自分のコードから、あるいはエージェントから。
詳細
- テンプレートは、それを書いた人ではなくコネクションに属する。これこそ最初のバージョンが置き換えられた理由そのものである。旧版はユーザーを軸にしていたため、同僚のテンプレートはワークスペースの API キーからは見えず、設定した本人に見えているものをインテグレーションからは送信できなかった。さらに、作成者のアカウントを削除すると、ワークスペースのテンプレートも一緒に消えた。行は破棄せずに引き継いである。
- 本文の書き方は 2 通りある。1 つは
@react-email/componentsのコンポーネント(Section, Row, Column, Container, Text, Heading, Button, Link, Img, Hr, Markdown, CodeBlock, CodeInline)で構成するブロックツリーで、書いた時点で検証されるため、不正なノードや安全でないhrefは、壊れたメールとして届く代わりに、それを書き込んだ呼び出しの時点で拒否される。もう 1 つは自分でレンダリングしたマークアップである。テンプレートが自分のリポジトリにある react-email のコンポーネントとして既に存在するなら、そちらで@react-email/renderを使ってレンダリングし、その HTML を送ればよい。HTML はバージョンの公開時に一度だけサニタイズされる。 - 23 個の出発点と、白紙が 1 つ。メニューではなくギャラリーに並ぶ。これらは選ぶ前に実際に見る必要があるものなので、どのカードもメールそのものを表示する。ウェルカムと確認、レシートと請求書、発送と更新、ダイジェストとお知らせが 4 つの見出しの下に並び、どれもビジュアルエディタで開いて、あらゆる要素を移動・再スタイル・削除できる。どれを選んでもドラフトとして届くので、公開するまでは何も送信できない。
- ギャラリーは、この機能のうちアプリにしかない唯一の部分である。自分のコードやエージェントからテンプレートに到達する呼び出し側は、出発点を名前で指定するのではなく本文(ブロックドキュメントか自前のマークアップ)を投稿する。したがって 23 個は、そこからインストールするカタログではなく、始めるための場所である。
- 名前付きの slot と名前付きの prop が、穴の 2 種類であり、本文と件名の中に {{key}} として書く。slot はテンプレートを編集する人が埋めるもので既定値を持つため、何も指定しない送信でもレンダリングできる。prop は送信時に渡すもので、required を付けたものが欠けていれば送信を拒否する。422 を返し、メールは 1 通も出ていかない。その拒否こそが宣言する目的である。そうでなければ、注文番号があるべき場所が空白のままメッセージが出ていき、それを報告する仕組みもなければ、取り消せる人もいない。
- 公開済みのバージョンは凍結される。公開済みテンプレートの本文を編集すると、稼働中のものを書き換えるのではなく新しいドラフトが作られる。そのため、誰かが公開するまで送信は昨日と同じものを解決し続け、バージョン番号を固定した送信は公開後も影響を受けない。本文は公開時にコンパイルされる。これにより、レンダリングできないテンプレートは、受信者ではなく公開する人のところで失敗する。
- プレビューは、送信せずに送信結果とまったく同じものをレンダリングし、まだ空のものを拒否せずに報告する。プレビューされているテンプレートはたいてい書きかけのテンプレートであり、1 ブロックずつ埋めている作者が、いまの状態を見るためにすべての prop を満たす必要はない。
- どのテンプレートも、自分が何を送ったかの記録を持つ。直近 7 日・30 日・90 日に何通出ていったか、そのうちどれが開封されどれがクリックされたか、日ごとの推移、そして各送信がどこから来たか(コンポーザー、自分のコード、エージェント、キュー)の内訳である。各率は他から借りるのではなく、それぞれの分母を示す。これらは本当に別物だからだ。開封はピクセルを載せたメッセージを母数として数え、クリックは書き換えたリンクを載せたメッセージを母数として数える。片方だけを載せたメッセージもあり得る。プレビューは一切記録されず、テスト送信は別に数えられて、どの数値からも除外される。実際には出ていっていないからだ。
- この記録は、見えないものについて正直であり、だからこそ見える半分は信頼できる。送信は送信そのものによって配信記録と突き合わされるが、その記録を持つのは自分のコードかキューから送ったメールだけである。コンポーザーから、エージェントから、あるいはアシスタントによって送られたメッセージは持たない。したがって、主にコンポーザーから使われているテンプレートは、送信の大半が未突合のまま並ぶ。その未突合の件数は「誰も開かなかった」として畳み込まれるのではなく、独立した数値として表示される。
- 1 つのサービスの上に 4 つの面があり、そのため「公開とは何を意味するのか」への答えは、今日はたまたま一致している 3 つではなく 1 つである。コンポーザーの Templates ボタンは公開済みのものを提示し、選んだものを貼り付けるのではなくメッセージを置き換える。送信はテンプレートを名指しし、バージョンは選んだ時点で固定され、本文は作成された場所でレンダリングされる。そのため、選んでからクリックするまでの間に公開が行われても送信内容は変わらず、コンポーザーでは保持できなかったレイアウトもそのまま残る。そこで入力するのは値であって、本文ではない。/templates は templates:read と templates:write のスコープの背後にある 9 つのエンドポイントで、SDK がメソッド単位でラップしている。送信にはテンプレートの権限に加えて送信の権限が必要なので、コピーライティングツールに発行したキーは、誰にもメールを送れないまま作成と公開ができる。MCP サーバーは 5 つのツール(一覧、取得、プレビュー、作成、送信)を備える。既存のものを更新・削除・公開するツールは意図的に存在しない。編集は次の送信が解決しないドラフトを生み、削除は取り消せないからだ。保存された本文の編集は画面の仕事である。/workspace/templates にはパレットとインスペクタを備えたブロックキャンバス、その横にライブプレビュー、そして別々の操作としての Save と Publish があり、これによって公開済みのバージョンは、次のものに取り組む間そのまま放っておけるものになる。
- コネクションあたり 200 テンプレート、ブロックドキュメントは 500 ブロックまで、ネストは 8 階層まで、1 つの値は 20,000 文字まで、slot は 100 個、prop は 100 個まで。マークアップとして投稿した本文は 100 万文字まで、件名は 998 文字まで。いずれもプラン上の制限ではなく暴走したスクリプトへの歯止めであり、いずれも拒否の理由となった数値を示すメッセージで拒否する。テンプレートに関して、ティアの背後にあるものは 1 つもない。