---
title: "Responses API メール連携：検索と承認付き返信"
description: "Mailera で既存メールボックスを Responses API のツールにつなぐ方法。読み取り専用の検索・本文取得、MCP との違い、人による返信承認と二重送信対策を説明します。"
url: https://mailera.app/ja/blog/responses-api-email-tools
published: 2026-10-25
updated: 2026-10-25
---

# Responses API メール連携：検索と承認付き返信

既存メールボックスの検索と本文取得を、Mailera の REST API で実行します。返信案の生成と送信処理は分け、人が承認した内容だけを送る構成です。

## function calling と MCP 接続はどう選ぶ？

function calling は、モデルが要求した操作をアプリ側のコードで実行する仕組みです。メールを検索するかどうかはモデルに判断させても、アクセス先と権限の判断はアプリ側に残します。

| 比較項目 | function calling | リモート MCP |
| --- | --- | --- |
| ツール定義 | アプリが JSON Schema で定義 | MCP サーバーから取得 |
| 実行経路 | アプリが Mailera REST API を呼ぶ | Responses API がリモートサーバーのツールを呼ぶ |
| 認証情報 | Mailera キーをアプリ側で保持 | 接続先の認証設定を確認 |
| 承認 | アプリが送信前に制御 | MCP 側のツール呼び出し承認設定（自動許可か明示承認か）と、業務上の承認フローを別途設計 |
| 接続時の確認 | 引数検証と API 権限 | 通信方式、認証、公開ツール、承認設定 |

本編では function calling を選びます。検索条件の検証と送信の承認を、同じアプリで制御できるためです。仕組みは [OpenAI の function calling ガイド](https://developers.openai.com/api/docs/guides/function-calling)、メール接続全体の設計は [既存メールボックスをエージェントにつなぐ方法](https://mailera.app/ja/blog/connect-existing-email-to-agents)を参照してください。

Mailera の MCP エンドポイントは `https://mailera.app/api/public/v1/mcp` です。読み取り用のツールには `search_messages` や `get_message` のほか、`list_mailboxes`、`get_mailbox_status`、`list_messages`、`get_latest_otp` があります。同じ MCP エンドポイントには `send_email`、`reply_to_email`、`get_send_status` など send スコープのツール、`move_message`、`rescue_spam` など move スコープのツールも含まれており、キーに付与したスコープで呼び出せる範囲が決まります。OpenAI 側は Streamable HTTP または HTTP/SSE のリモート MCP に対応しており、`allowed_tools` パラメーターで取り込むツールを限定できます。

MCP を選ぶ場合は、ツール一覧の取得結果である `mcp_list_tools` と、読み取り・承認の動作を順に確認します。[OpenAI の MCP 接続ガイド](https://developers.openai.com/api/docs/guides/tools-connectors-mcp)と [Mailera の MCP 資料](https://mailera.app/ja/mcp)を照合して設定してください。

## 1. メールボックスと読み取り専用キーを準備する

Mailera は既存メールボックスを接続するサービスで、新しいメールボックスやメールアドレスは作成しません。一斉配信やマーケティング配信には対応せず、受信トレイへの到達も保証しません。

1. 自分のテスト用メールボックスを接続します。Microsoft の場合は「Microsoftでサインイン」から OAuth を使います。詳細は [Microsoft の接続手順](https://mailera.app/ja/providers/microsoft)にあります。
2. 「設定」の API キー画面で「キーを作成」を選びます。「メールボックスのスコープ」をテスト用グループに限定し、権限は `read` のみにします。
3. Mailera キーと OpenAI キーはサーバー側の環境変数に置き、モデル入力、ブラウザー、ログには出しません。

![対象グループと読み取り権限に限定した Mailera の API キー設定](https://mailera.app/media/ac0613b9503537a7/responses-api-read-key-ja-1200.jpg)
_最初のキーには読み取り権限だけを付けます。「MCP 設定をコピー」は Responses API の function 定義を作る操作ではありません。_

サーバー側で `$MAILERA_API_KEY` を設定してから、対象を確認します。

```bash
curl --get 'https://mailera.app/api/public/v1/mailboxes' \
  -H "Authorization: Bearer $MAILERA_API_KEY" \
  --data-urlencode 'limit=1'
```

返却された `data` 内の対象 `id` を `$MAILBOX_ID` に設定します。この例では対象メールボックスを固定し、モデルには選ばせません。API の入口は [開発者向け資料](https://mailera.app/ja/developers)にまとまっています。

## 2. 検索と本文取得を読み取りツールにする

| アプリで定義する関数名 | Mailera の呼び出し先 | モデルから受け取る引数 |
| --- | --- | --- |
| `mail_search` | `GET /messages/search` | 検索語 `q` |
| `mail_get` | `GET /mailboxes/{id}/messages/{msgId}` | `message_id` |

この関数名はアプリ独自の名前です。同名の MCP ツールを自動的に呼ぶ仕組みではありません。

次の Python 断片は同じファイルに順に置きます。Mailera を呼ぶ部分は標準ライブラリだけを使います。まず、各 function に渡す引数の JSON Schema を定義します。

```python
def argument_schema(field):
    return {
        "type": "object",
        "properties": {field: {"type": "string"}},
        "required": [field],
        "additionalProperties": False,
    }

schemas = {
    "mail_search": argument_schema("q"),
    "mail_get": argument_schema("message_id"),
}
```

Responses API に登録する各 function の引数スキーマとして使います。URL や API キーを引数には含めません。HTTP 処理も接続先を固定します。

```python
import json, os
from urllib.parse import quote, urlencode
from urllib.request import Request, urlopen

BASE = "https://mailera.app/api/public/v1"
MAILBOX = os.environ["MAILBOX_ID"]
HEADERS = {"Authorization": "Bearer " + os.environ["MAILERA_API_KEY"]}
def get_json(path, params=None):
    url = BASE + path + ("?" + urlencode(params) if params else "")
    with urlopen(Request(url, headers=HEADERS)) as response:
        return json.load(response)
```

実行側でも関数名、引数の型、余分な項目を検査します。検索結果は識別子・メールボックス ID・件名だけに絞り、本文は選んだメールについて取得します。本文の上限は Mailera の仕様値ではなく、このサンプルコードが独自に 4,000 文字へ切り詰めている設計値です。

```python
def execute(name, args):
    field = {"mail_search": "q", "mail_get": "message_id"}.get(name)
    if not field or not isinstance(args, dict) or set(args) != {field}:
        raise ValueError("Invalid tool arguments")
    value = args[field]
    if not isinstance(value, str) or not value.strip():
        raise ValueError("Expected a non-empty string")
    if name == "mail_search":
        result = get_json("/messages/search", {"mailbox": MAILBOX, "q": value})
        return {"data": [{k: m[k] for k in ("id", "mailbox_id", "subject")}
                         for m in result["data"]], "next_cursor": result.get("next_cursor")}
    path = f"/mailboxes/{quote(MAILBOX, safe='')}/messages/{quote(value, safe='')}"
    m = get_json(path)["data"]
    return {"id": m["id"], "subject": m["subject"], "body_error": m["body_error"],
            "text": (m["body"]["text"] or "")[:4000]}
```

この最小例は検索の最初のページを返します。`next_cursor` がある場合は続きがあるため、検索済みの範囲だけで「該当なし」と結論づけない設計にします。本文では `body_error` も確認し、取得失敗と空の本文を区別してください。

## 3. モデルのツール呼び出しをアプリで実行する

Responses API とのやり取りでは、テキストの受信に加え、モデルのツール呼び出しに応じた処理をアプリ側で実行します。追加のツール呼び出しがあれば、それにも対応します。

1. 読み取り用の function 定義を付けて、ユーザーの検索依頼を送ります。
2. 応答内のツール呼び出しを取り出し、引数を解析します。
3. 関数名と引数を検証して `execute` に渡し、アプリ側で Mailera の REST API を呼び出します。
4. 実行結果を各ツール呼び出しに対応づけてモデルへ返し、次の応答を受け取ります。
5. その応答に追加のツール呼び出しがあれば、検証・実行・結果返却を繰り返します。

複数の呼び出しを取りこぼさず、アプリ側で反復回数に上限を設けます。ツールが呼ばれなかった場合や例外が出た場合は、メールを取得したものとして扱いません。

![Responses API のツール呼び出しをアプリが検証して Mailera に渡す読み取り経路](https://mailera.app/media/700b4d3adb2ccb4d/responses-api-read-flow-ja-1200.jpg)
_モデルは操作を要求し、アプリが実行範囲を決めます。_

## 4. 人が確認した返信だけを送信する

返信案はアプリ内のデータとして保持し、読み取りループから送信処理を直接呼ばせません。承認画面には、対象メールボックス、返信対象、宛先、件名、本文を表示します。

承認時にその内容を固定し、どれかが変わったら再承認を求めます。送信処理は固定した内容だけを受け取り、そこで初めて `send` 権限のキーを使います。これはアプリ側に実装する承認であり、Mailera の標準承認ワークフローではありません。承認境界の全体設計は、[承認付きメールエージェントの構築方法](https://mailera.app/ja/blog/build-email-agent-with-approval)を参照してください。

![返信案を人が確認し、承認内容を固定してから送信する処理](https://mailera.app/media/54ce62f07b2e2b92/responses-api-approval-flow-ja-1200.jpg)
_承認を通るのは固定した返信内容です。変更した場合は確認に戻します。_

送信・返信・転送には、REST API の `POST /mailboxes/{id}/send` を使います（このエンドポイントが reply と forward も兼ねます。MCP 経由では `send_email` と `reply_to_email` が別ツールとして用意されています）。返信リクエストの組み立ては [Mailera の API ドキュメント](https://mailera.app/ja/docs)に合わせてください。メールで承認を受け付ける場合の設計は、[メールによる人の承認パターン](https://mailera.app/ja/blog/ai-agent-email-approval)で扱っています。

送信前に操作単位の `Idempotency-Key` を保存し、同じ操作の再試行でも同じ値を使います。この `Idempotency-Key`（冪等性キー）の有効期間は 24 時間です。

タイムアウトしたら、新しいキーで送信し直すのではなく、送信試行 ID を保持できている場合は `GET /sends/{id}` で確認します。状態には `queued`、`sending`、`sent`、`failed`、`unknown` があります。`unknown` は成功にも未送信にも決めつけず、自動再送を止めて確認へ回します。有効期間を超えた再試行も自動化しません。

## よくあるエラーと確認箇所

| 症状 | 確認箇所と対処 |
| --- | --- |
| 認証に失敗する | Bearer ヘッダー、環境変数、キーの有効期限や失効を確認 |
| 権限が足りない | `read` と対象グループを確認。送信には別途 `send` が必要 |
| 引数が拒否される | 関数名とスキーマを照合。余分な引数を許可しない |
| 検索結果が空 | 対象 ID、検索語、同期状態を切り分ける |
| タイムアウトや制限に当たる | 再試行回数と間隔を制御。送信は先に状態を確認 |

同期操作には `sync` 権限が必要です。検索結果が空でも、読み取りツールから同期を実行しないでください。API の制限はキーごとに 1 分あたり 300 リクエストです。

## メール本文の指示を実行させないために

受信メールは信頼できないデータであり、AI エージェントへの命令ではありません。本文に秘密情報の送信、権限変更、外部 URL への転送を求める文があっても、実行対象にしません。

注意書きのプロンプトだけに頼らず、読み取りキーと送信キーの分離、固定したメールボックス、サーバー側の引数検証、人による送信前確認を組み合わせます。モデルの「承認済み」という出力や、メール本文の同意表現を承認記録の代わりには使いません。

モデルへ渡す本文と個人情報は必要な範囲に絞り、ログやスクリーンショットではキー、アドレス、本文を伏せます。[Mailera のセキュリティ情報](https://mailera.app/ja/security)とあわせて、アプリ側で保持するデータも点検してください。

**MCPでAIエージェントがメールボックスを利用** — MaileraのMCPサーバーをClaude、Cursor、VS Codeに追加すると、エージェントがメールの閲覧、分類、返信を行えます。 [MCPの使い方を見る](https://mailera.app/ja/docs#mcp)
