コンテンツにスキップ

メール API

メールテンプレートの管理と、候補者へのメール送信・プレビュー・送信ログ。共通規約は API 共通仕様 を参照。

エンドポイント一覧

ベースパスが 3 つに分かれている。

/api/v1/email-templates(システム共通テンプレート)

メソッド パス 概要 必要ロール
GET / システムテンプレート一覧取得 viewer

/api/v1/projects/{projectId}/email-templates(プロジェクト個別テンプレート)

メソッド パス 概要 必要ロール
GET / プロジェクトテンプレート一覧取得 viewer
POST / テンプレート作成 member
PATCH /{templateId} テンプレート更新 member
DELETE /{templateId} テンプレート削除 member
POST /preview テンプレートプレビュー member
POST /send テンプレートでメール送信 member

/api/v1/projects/{projectId}/emails(送信とログ)

メソッド パス 概要 必要ロール
GET /logs メール送信ログ一覧取得 viewer
POST /send メール一括送信 member
POST /preview メールプレビュー member

全エンドポイントで Authorization: Bearer <access_token> が必要。更新系は member 以上。

/email-templates/send と /emails/send は同一の入出力

プレビューと送信は 2 系統に同じものが用意されている。どちらを使っても動作は同じ。

EmailTemplate オブジェクト

フィールド 型 説明
id integer テンプレート ID
projectId integer | null NULL ならシステム共通
type enum invitation / reminder / confirmation / cancellation
name string テンプレート名
subject string 件名(プレースホルダ可)
body string 本文(プレースホルダ可)
createdAt / updatedAt string(date-time) 作成/更新日時

プレースホルダ

件名・本文には差し込み用のプレースホルダを埋め込める。

プレースホルダ 差し込まれる値
{{candidate_name}} 候補者の氏名
{{project_name}} プロジェクト名

実際に利用可能なプレースホルダは services/email.ts の実装に従う。差し込み結果は「プレビュー」で確認できる。


システムテンプレート一覧取得

project_id が NULL のテンプレート(全プロジェクト共通)を返す。

URI

GET /api/v1/email-templates

レスポンス(200 OK)

data が EmailTemplate の配列(ページネーションなし)。

例外処理

説明 ステータスコード ステータス名
トークンが欠落または無効 401 Unauthorized
サーバ内部エラー 500 Internal Server Error

プロジェクトテンプレート一覧取得

URI

GET /api/v1/projects/{projectId}/email-templates

レスポンス(200 OK)

data が EmailTemplate の配列。

{
  "success": true,
  "status": "success",
  "statusCode": 200,
  "data": [
    {
      "id": 1,
      "projectId": 1,
      "type": "invitation",
      "name": "初回案内",
      "subject": "【{{project_name}}】インタビューのご案内",
      "body": "{{candidate_name}} 様\n\nこの度は...",
      "createdAt": "2026-01-15T09:00:00Z",
      "updatedAt": "2026-01-15T09:00:00Z"
    }
  ],
  "path": "/api/v1/projects/1/email-templates",
  "method": "GET"
}

例外処理

説明 ステータスコード ステータス名
トークンが欠落または無効 401 Unauthorized
プロジェクトが存在しない 404 Not Found

テンプレート作成

URI

POST /api/v1/projects/{projectId}/email-templates

リクエストボディ

{
  "type": "invitation",
  "name": "初回案内",
  "subject": "【{{project_name}}】インタビューのご案内",
  "body": "{{candidate_name}} 様\n\nこの度はご協力ありがとうございます。"
}

バリデーションルール

フィールド ルール
type 必須。invitation / reminder / confirmation / cancellation
name 必須。1〜255 文字
subject 必須。1〜500 文字
body 必須。1 文字以上

レスポンス(201 Created)

data に作成された EmailTemplate。

例外処理

説明 ステータスコード ステータス名
バリデーションエラー 400 Bad Request
トークンが欠落または無効 401 Unauthorized
ロール不足 403 Forbidden
プロジェクトが存在しない 404 Not Found

テンプレート更新

URI

PATCH /api/v1/projects/{projectId}/email-templates/{templateId}

パスパラメータ

フィールド ルール
templateId 必須。正の整数

リクエストボディ

作成時の全フィールドが任意になる。

{
  "subject": "【{{project_name}}】インタビュー日程のご相談"
}

レスポンス(200 OK)

data に更新後の EmailTemplate。

例外処理

説明 ステータスコード ステータス名
バリデーションエラー 400 Bad Request
トークンが欠落または無効 401 Unauthorized
ロール不足 403 Forbidden
テンプレートが存在しない 404 Not Found

テンプレート削除

URI

DELETE /api/v1/projects/{projectId}/email-templates/{templateId}

レスポンス(204 No Content)

ボディなし。

例外処理

説明 ステータスコード ステータス名
トークンが欠落または無効 401 Unauthorized
ロール不足 403 Forbidden
テンプレートが存在しない 404 Not Found

Note

email_logs.template_id には外部キー制約がないため、テンプレートを削除しても送信ログは残る。


メールプレビュー

1 候補者に対する差し込み結果を返す。送信は行わない。

URI

POST /api/v1/projects/{projectId}/email-templates/preview
POST /api/v1/projects/{projectId}/emails/preview

リクエストボディ

{
  "templateId": 1,
  "candidateId": 12
}

バリデーションルール

フィールド ルール
templateId 必須。正の整数
candidateId 必須。正の整数(project_candidates.id)

レスポンス(200 OK)

{
  "success": true,
  "status": "success",
  "statusCode": 200,
  "data": {
    "subject": "【2026年春季ユーザーインタビュー】インタビューのご案内",
    "body": "山田太郎 様\n\nこの度はご協力ありがとうございます。",
    "to": "yamada@example.com"
  },
  "path": "/api/v1/projects/1/emails/preview",
  "method": "POST"
}

例外処理

説明 ステータスコード ステータス名
バリデーションエラー 400 Bad Request
トークンが欠落または無効 401 Unauthorized
ロール不足 403 Forbidden
テンプレートまたは候補者が存在しない 404 Not Found

メール一括送信

URI

POST /api/v1/projects/{projectId}/email-templates/send
POST /api/v1/projects/{projectId}/emails/send

リクエストボディ

{
  "templateId": 1,
  "candidateIds": [12, 34, 56]
}

バリデーションルール

フィールド ルール
templateId 必須。正の整数
candidateIds 必須。正の整数の配列。1 件以上

レスポンス(200 OK)

送信結果は成功/失敗の件数と、失敗した候補者の明細で返る。

{
  "success": true,
  "status": "success",
  "statusCode": 200,
  "data": {
    "sent_count": 5,
    "failed_count": 1,
    "errors": [
      { "candidateId": 56, "email": "invalid@example", "message": "メールアドレスが不正です" }
    ]
  },
  "path": "/api/v1/projects/1/emails/send",
  "method": "POST"
}

このレスポンスは snake_case

sent_count / failed_count は camelCase ではない。

例外処理

説明 ステータスコード ステータス名
バリデーションエラー(candidateIds が空など) 400 Bad Request
トークンが欠落または無効 401 Unauthorized
ロール不足 403 Forbidden
テンプレートまたはプロジェクトが存在しない 404 Not Found
送信失敗(EMAIL_SEND_ERROR) 500 Internal Server Error

副作用

  • 送信ごとに email_logs に差し込み後の件名・本文が記録される
  • 案内メール(invitation)の送信では調整トークン(scheduling_tokens)が発行され、URL が本文に差し込まれる
  • 候補者のステータスが遷移する場合がある

PROTOTYPE_MODE

PROTOTYPE_MODE=true(既定)の間は 実際のメール送信が行われない。判定は isEmailEnabled() による。


メール送信ログ一覧取得

URI

GET /api/v1/projects/{projectId}/emails/logs

クエリパラメータ

フィールド 型 必須 既定値 ルール
page integer - 1 正の整数
limit integer - 20 1〜100
sort string - - -

レスポンス(200 OK)

data が EmailLog の配列、pagination 付き。

{
  "success": true,
  "status": "success",
  "statusCode": 200,
  "data": [
    {
      "id": 1,
      "projectCandidateId": 12,
      "templateId": 1,
      "subject": "インタビューのご案内",
      "body": "山田太郎 様...",
      "sentAt": "2026-01-15T09:00:00Z",
      "status": "sent",
      "sentBy": 1,
      "candidateName": "山田太郎",
      "candidateEmail": "yamada@example.com",
      "senderName": "管理者"
    }
  ],
  "pagination": { "page": 1, "limit": 20, "totalCount": 42, "totalPages": 3, "hasNext": true, "hasPrevious": false },
  "path": "/api/v1/projects/1/emails/logs",
  "method": "GET"
}
フィールド 型 説明
id integer ログ ID
projectCandidateId integer 宛先の候補者
templateId integer | null 使用テンプレート
subject / body string 差し込み後の件名・本文
sentAt string(date-time) 送信日時
status enum sent / delivered / bounced / failed
sentBy integer 送信操作を行ったユーザー ID
candidateName / candidateEmail string | null 候補者情報(結合結果)
senderName string | null 送信者名(結合結果)

例外処理

説明 ステータスコード ステータス名
トークンが欠落または無効 401 Unauthorized
プロジェクトが存在しない 404 Not Found

候補者 1 人分の履歴は 候補者 API の GET /{candidateId}/email-logs を使う。