email-generation について
email-generationは、固定のメールシーケンスと入力済みの連絡先CSVを、レビュー用および配信用形式に変換するレンダラーです。バリアント選択やフィールド置換、出力検証を行い、LLMによる文面生成は行いません。
主な機能
- 01行のキーに基づくメールバリアント選択
- 02宣言済みのフォールバックを伴うフィールド置換
- 03レビュー用・HTML・プレーンテキスト本文の生成
- 04プレースホルダーと出力品質の検証
- 05メールCSVと人が読めるレビュー文書の出力
- 06キャンペーンの抑制リストへの準拠
活用シーン
- 01連絡先ごとのキャンペーンシーケンスのレンダリング
- 02HTMLおよびレビュー用メール出力の作成
- 03テンプレートや入力データの修正後の再レンダリング
- 04出力前の抑制対象連絡先の除外
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ extruct-ai/ gtm-skills --skill email-generationインストール後、Claude Code で/email-generationを入力して読み込まれたか確認します。
同梱ファイルreferences/render_emails.py
詳細
メール生成(レンダラー)
固定のテンプレートセット(email-prompt-building の sequence.md)と、{{input_fields}} がすでに入力済みの連絡先 CSV から、一連のメールをレンダリングします。このスキルは機械的な処理を行います。バリアントを振り分け、プレースホルダーを置換し、出力形式にレンダリングして、出力 CSV を書き出します。
**ここでは LLM を呼び出しません。**戦略的な推論はすべて設計時(email-prompt-building)に行われ、行ごとの処理に必要な情報はすべて、上流の正規化とエンリッチメントによって入力フィールドに設定されています。メールに誤りがある場合は、テンプレートか入力データに問題があります。ソースを修正して、再レンダリングしてください。
アーキテクチャの原則
このスキルはレンダラーであり、推論するものでも実行を制御するものでもありません。
template set (sequence.md) ─┐
├──▶ route variant ─▶ substitute ─▶ render to target ──▶ emails CSV
contact CSV (fields filled) ┘
必要な入力
| 入力 | ソース | 必須 |
|---|---|---|
| テンプレートセット | email-prompt-building のキャンペーン用シーケンスファイル | はい |
| 連絡先 CSV | 正規化とエンリッチメントによって入力フィールドがすでに設定済み | はい |
連絡先 CSV には、ルーティングキーとともに、テンプレートの「Input Fields」コントラクトに記載されたすべてのフィールドを含める必要があります。行に宣言済みフィールドがない場合は、そのフィールドに定義されたフォールバックを適用してください。データを補えない行は削除し、その旨を報告してください。
レンダリングコントラクト
このパイプラインで実際に問題が発生するのは、レンダリングの段階です。「プレースホルダーを置換する」という説明では、改行とエスケープという難所が曖昧なままです。このコントラクトは必須です。
改行モデル
テンプレートでは 2 種類の改行を使い分けているため、レンダラーはその違いを必ず保持する必要があります。
\n\n(空行) = 段落区切り\n(単独) = 段落内のソフト改行(意図的に使用)
レンダリング先 — 本文は 1 つ、出力は 3 種類
| 対象 | 改行の処理 | エスケープ |
|---|---|---|
review(emails.md / CSV の body 列) | \n\n と \n をそのまま保持 | なし。ただし、CSV ライターは複数行のセルを必ず引用符で囲む |
html(Instantly / シーケンサー) | \n → <br />(したがって、\n\n → <br /><br />) | コンテンツ内の & < > を HTML エスケープ |
plain(プレーンテキストのチャネル) | そのまま保持 | なし |
処理順 — 必ず守ること
- バリアントを振り分ける — ルーティングキー(例:
customer_segment)を使って、タッチのバリアントを選択します。 {{fields}}をプレーンテキストの本文に置換する。- 完成した文字列に対し、最後にエスケープと改行変換を行う。
この順序が必要な理由:置換前にテンプレートを HTML エスケープすると、Johnson & Johnson のようなフィールド値がエスケープされずに入り、HTML が壊れます。完成した文字列をエスケープすれば、テンプレート本文と置換後の値の両方を対象にできます。
レンダラーの実装例
import html
def render(body: str, target: str) -> str:
"""body: assembled plain-text (variant chosen, {{fields}} substituted).
target: 'review' | 'html' | 'plain'."""
if target in ("review", "plain"):
return body
if target == "html":
# escape content per line, THEN join with <br /> — never escape the tags
return "<br />".join(html.escape(line) for line in body.split("\n"))
raise ValueError(target)
レンダラーが防ぐべき失敗
- バグ第 1 位 —
\n→<br>の変換忘れ:メールが文字の塊として届きます。HTML シーケンサーでは必ず変換してください。 - 置換前のエスケープ —
& < >を含むフィールド値で HTML が壊れます。 - 二重エスケープ —
&amp;になります。最後の手順で、1 回だけエスケープしてください。 - 複数行の CSV セルを引用符で囲まない —
body列内の改行によって、行や列がずれます。適切な CSV ライターを使用してください。 - 未置換のプレースホルダー — 書き出す前に、出力内に
{{が一つも残っていないことを必ず検証してください。{{company_name}}が残っている場合、そのフィールドが渡されていません(例:Touch 3 にcompany_nameが渡されていない)。
ワークフロー
ステップ 1:入力を検証する
- テンプレートセットを読み込み、すべての
{{field}}とルーティングキーを収集します。 - 連絡先 CSV のヘッダーを読み込み、宣言済みのすべての入力フィールドとルーティングキーが含まれていることを確認します。
- 不一致があれば報告し、レンダリングを始める前に停止します。
ステップ 2:行ごとにレンダリングする
各連絡先について、各タッチで次の処理を行います。
- タッチにバリアントがある場合は、バリアントを振り分けます。
- 入力フィールドをプレーンテキストの本文に置換し、値が空の場合はフィールドごとのフォールバックを適用します。
- 必要な各対象(
review、html)にレンダリングします。 {{が残っていないことを検証します。
件名:最初のタッチにのみ設定します。フォローアップではスレッドを継続するため、件名は空にします。
ステップ 3:出力を書き出す
- メールの CSV — (連絡先 × タッチ)ごとに 1 行:
email, first_name, company_name, touch, variant, subject, body, body_html, gaps。gaps列には、フォールバックしたフィールドを記録します(例:industry=fallback)。 - 人が読みやすいレビュー用ファイル — セクションごとにメールを 1 通記載します。
両方とも、GTM プロジェクトのキャンペーンアセットの保存先に書き出します。参照用レンダラーについては、references/render_emails.py を参照してください。
ステップ 4:品質チェック
- すべての行で未置換の
{{が 0 個 - バリアントの振り分けが正しい — 各バリアントにつき 1 行をスポットチェック
-
\n\nと\nがどちらも HTML 出力に<br /><br />/<br />として保持されている -
&/<を含むフィールド値がエスケープされて出力される(生のままでも二重エスケープでもない) - 行数 = 連絡先 × タッチ数。フォールバックが適用された箇所では
gapsが入力されている - フォローアップのタッチでは件名が空
フィードバックループ
ユーザーからメールの問題が指摘された場合:
- コピーの問題(→
email-prompt-buildingを使ってテンプレートを修正)か、データの問題(→ 入力フィールドが正しくなるように正規化/エンリッチメントを修正)かを特定します。 - 再レンダリングします。個別のメールを手作業で編集してはいけません。修正箇所は必ずテンプレートか入力データです。
抑制リスト
出力 CSV を書き出す前に、GTM プロジェクトの抑制リストにメールアドレスが登録されている連絡先を除外します(配信停止、バウンス、使用停止アドレス)。このリストの保存場所はプロジェクト側で管理します。このスキルはリストに従うだけです。
まだテンプレートがありませんか?
キャンペーン用の sequence.md がない場合は、email-prompt-building スキルを使って設計します。このスキルでコピーを即興で作成してはいけません。このスキルはレンダリングのみを行います。