毎朝メールボックスを開いて、同じような内容のメールに何度も返信し続ける作業——個人開発をしながらサイト運営もしていると、このルーティンがいかに時間を食うかを実感します。問い合わせ、コラボ提案、技術的な質問。内容はそれぞれ違うように見えて、実は5〜6パターンに収まることが多いんですよね。
そこで試したのが、Claude APIとGoogle Apps Script(GAS)の組み合わせです。GASはGoogleアカウントさえあれば無料で使えて、Gmailとの連携が驚くほどスムーズです。Claude APIを繋ぐだけで、メールの分類と返信下書きの自動生成が実現できます。
なぜGoogle Apps ScriptとClaude APIなのか
メール自動化のツールはたくさんあります。Zapier、Make(旧Integromat)、n8nなど。ただ、いずれも月額費用がかかるか、設定の自由度に限界があります。
GAS + Claude APIの組み合わせが気に入っている理由は3つです。
まず、GASはGoogleのサーバーで動くため、自分のサーバーが不要です。毎分・毎時間トリガーで自動実行でき、維持コストはほぼゼロ。次に、Gmailとの連携APIが充実していること。未読メールの取得、ラベル付け、下書き作成まで、数行のコードで実現できます。そして、Claude APIの費用が現実的なこと。Claude APIの料金体系を見ると、1日数十通程度のメール処理ならHaiku 4.5で月数十円〜数百円に収まります。
事前準備 — Claude APIキーの取得とGASプロジェクトの作成
Claude APIキーの取得:
Anthropic Console にログインして「API Keys」からキーを発行します。キーは sk-ant-... 形式です。
GASプロジェクトの作成:
- script.google.com にアクセスして「新しいプロジェクト」を作成
- 左側の「⚙️ プロジェクトの設定」→「スクリプトプロパティ」で
CLAUDE_API_KEYとしてキーを保存(コードに直接書かないこと)
プロパティへの保存でAPIキーを安全に管理できます。
Gmailのメールを取得してClaudeに送る
GASでGmailの未読メールを取得し、Claude APIに送る基本コードです。
/**
* 未読メールを取得してClaudeで処理する
* GAS トリガー:時間ベース(毎時間実行推奨)
*/
function processUnreadEmails() {
const apiKey = PropertiesService.getScriptProperties()
.getProperty('CLAUDE_API_KEY');
// 未読メールを最大10件取得(過去24時間以内)
const threads = GmailApp.search('is:unread newer_than:1d', 0, 10);
if (threads.length === 0) {
console.log('未読メールなし');
return;
}
threads.forEach(thread => {
const messages = thread.getMessages();
const latestMessage = messages[messages.length - 1];
// 自動送信メールをスキップ(メルマガ・通知系)
const from = latestMessage.getFrom();
if (isAutoSentEmail(from)) {
latestMessage.markRead();
return;
}
const subject = latestMessage.getSubject();
const body = latestMessage.getPlainBody().slice(0, 2000); // 最大2000文字
// Claudeで分類と返信生成
const result = classifyAndDraftReply(apiKey, subject, body, from);
// Gmailにラベルを付けて下書きを作成
applyLabelAndCreateDraft(thread, latestMessage, result);
latestMessage.markRead();
});
}
/**
* 自動送信メールの簡易判定
*/
function isAutoSentEmail(from) {
const autoPatterns = [
'noreply', 'no-reply', 'donotreply',
'notification', 'newsletter', 'mailer-daemon'
];
return autoPatterns.some(pattern =>
from.toLowerCase().includes(pattern)
);
}メール分類と返信下書きをClaudeで生成する
Claude APIへのリクエスト部分です。1回のAPI呼び出しで分類と返信の両方を生成することで、コストと処理時間を節約します。
/**
* Claude APIを呼び出してメールを分類し返信下書きを生成する
* @returns {Object} { category, priority, draftReply }
*/
function classifyAndDraftReply(apiKey, subject, body, from) {
const prompt = `
以下のメールを分析してください。
送信者: ${from}
件名: ${subject}
本文:
${body}
以下のJSON形式で回答してください:
{
"category": "inquiry|collaboration|technical|spam|other",
"priority": "high|medium|low",
"summary": "30文字以内の要約",
"draftReply": "返信下書き本文(敬語・200文字以内)"
}
カテゴリの説明:
- inquiry: 製品・サービスへの問い合わせ
- collaboration: コラボ・提案・依頼
- technical: 技術的な質問・バグ報告
- spam: 迷惑メール・セールス
- other: 上記以外
`;
const payload = {
model: 'claude-haiku-4-5-20251001',
max_tokens: 1024,
messages: [
{ role: 'user', content: prompt }
]
};
const options = {
method: 'post',
contentType: 'application/json',
headers: {
'x-api-key': apiKey,
'anthropic-version': '2023-06-01'
},
payload: JSON.stringify(payload),
muteHttpExceptions: true
};
try {
const response = UrlFetchApp.fetch(
'https://api.anthropic.com/v1/messages',
options
);
if (response.getResponseCode() !== 200) {
console.error('API エラー:', response.getContentText());
return { category: 'other', priority: 'low', draftReply: '' };
}
const data = JSON.parse(response.getContentText());
const content = data.content[0].text;
// JSONを抽出(コードブロックに包まれている場合を考慮)
const jsonMatch = content.match(/\{[\s\S]*\}/);
if (!jsonMatch) {
return { category: 'other', priority: 'low', draftReply: '' };
}
return JSON.parse(jsonMatch[0]);
} catch (error) {
console.error('処理エラー:', error.toString());
return { category: 'other', priority: 'low', draftReply: '' };
}
}claude-haiku-4-5-20251001 を使うのがポイントです。このタスクはメール分類と短い返信生成なので、Haikuで十分な品質が出ます。Sonnetを使うと費用が約5倍になりますが、体感品質の差はほとんどありません。
ラベル付けと下書き作成を自動化する
Claudeの分類結果をGmailに反映させます。
/**
* 分類結果に基づいてGmailにラベルを付け、返信下書きを作成する
*/
function applyLabelAndCreateDraft(thread, message, result) {
const { category, priority, summary, draftReply } = result;
// カテゴリラベルを取得または作成
const labelName = `AI分類/${category}`;
let label = GmailApp.getUserLabelByName(labelName);
if (!label) {
label = GmailApp.createLabel(labelName);
}
thread.addLabel(label);
// 優先度が高いメールには★ラベルを追加
if (priority === 'high') {
const highLabel = GmailApp.getUserLabelByName('AI分類/★要対応')
|| GmailApp.createLabel('AI分類/★要対応');
thread.addLabel(highLabel);
thread.markImportant();
}
// 返信下書きを作成(spamカテゴリは除外)
if (category !== 'spam' && draftReply) {
const replyBody = `${draftReply}\n\n---\n【AI生成下書き|${summary}】`;
GmailApp.createDraft(
message.getFrom(),
`Re: ${message.getSubject()}`,
replyBody,
{
threadId: thread.getId(),
inReplyTo: message.getId()
}
);
}
console.log(`処理完了: ${category} / ${priority} / ${summary}`);
}これを実行すると、Gmailのサイドバーに AI分類 というラベルグループが自動作成されます。inquiry(問い合わせ)collaboration(コラボ)technical(技術)など、カテゴリ別に自動整理されます。
実際につまずいたポイント3つ
1. UrlFetchApp の同期処理制限
GASの UrlFetchApp.fetch() はデフォルトで応答を待ちます。Claude APIのレスポンスが遅い場合(大量のメール処理時)、GASの実行時間制限(6分)に引っかかります。対策として、1回の実行で処理するメール数を10件以下に制限しています。
2. JSONのパース失敗
Claudeはほぼ確実にJSONを返しますが、たまに json ... のようなコードブロックで囲まれることがあります。そのため content.match(/\{[\s\S]*\}/) で正規表現を使ってJSONを抽出する処理を入れています。
3. レート制限エラー(429)
複数のGASトリガーが重複実行した場合、APIのレート制限に引っかかることがあります。Claude APIのレート制限対策を参考に、GASのトリガー設定を「毎時1回」に統一することで解決しました。重複実行が心配な場合は、スクリプトプロパティに lastRun タイムスタンプを保存して二重実行を防ぐガードも有効です。
まずは小規模から試してみてください
最初は「試しに1日分の未読メールだけ処理する」という形で始めると安心です。GASのスクリプトエディタから手動実行して、期待通りのラベルと下書きが生成されるかを確認してから、自動トリガーを設定する流れがおすすめです。
Sheetsとの連携についてはClaude APIとGoogle Apps Script でスプレッドシートを自動化するでも解説しているので、合わせて参考にしてみてください。コードは動作確認しながら、自分のメールボックスに合わせてカスタマイズしていくのが一番です。