スプレッドシートの宛先リストから、GASで名前を差し込んだメールを送る方法があります。
公式のリファレンスと割り当てをもとに、使うクラスと、1日の上限を整理しました。
- 送信には MailApp か GmailApp を使う
- 1日の上限は、受信者数で数える
- 無料アカウントは100、Google Workspaceは1,500が目安(公式の割り当て表)
- 残りの枠は、MailApp.getRemainingDailyQuota() で確認できる
公式資料に基づく説明と掲載コードのローカル検証を掲載しています。
上限や仕様は、Googleの都合で変わることがあります。
数値は、公式ページで最新を確かめてください。
MailAppとGmailApp
| MailApp | GmailApp | |
|---|---|---|
| 用途 | メール送信だけ | 送信に加え、Gmailの読み書きもできる |
| 必要なスコープ | script.send_mail | mail.google.com(権限が広い) |
送信だけなら、必要な権限が小さい MailApp が向いています。
宛名を差し込んで送る
function sendMails() {
const DRY_RUN = true; // 最初はtrue。確認後にfalseへ変更すると送信します。
const ss = SpreadsheetApp.getActiveSpreadsheet();
if (!ss) throw new Error('練習用スプレッドシートから開いてください。');
const sheet = ss.getSheetByName('送信練習');
if (!sheet) throw new Error('「送信練習」シートを作成してください。');
const lock = LockService.getScriptLock();
if (!lock.tryLock(5000)) throw new Error('別の送信処理が実行中です。');
try {
const lastRow = sheet.getLastRow();
if (lastRow < 2) return;
if (lastRow > 11) throw new Error('この練習例は最大10行です。');
const source = sheet.getRange(1, 1, lastRow, 3);
if (source.getFormulas().some(row => row.some(Boolean)) || source.isPartOfMerge()) {
throw new Error('A:Cは数式や結合セルのない練習表を使ってください。');
}
const headers = sheet.getRange(1, 1, 1, 3).getValues()[0];
if (JSON.stringify(headers) !== JSON.stringify(['名前', 'メールアドレス', '状態'])) {
throw new Error('見出しと列順を確認してください。');
}
const rows = sheet.getRange(2, 1, lastRow - 1, 3).getValues();
const pending = [];
const seen = new Set();
rows.forEach(function (row, index) {
const name = String(row[0]).trim();
const mail = String(row[1]).trim();
const state = String(row[2]).trim();
if (!name && !mail && !state) return;
if (state) return; // 送信済み・送信中など、状態のある行を再送しない
if (!name || name.length > 100 || mail.length > 254 || !/^[^\s@,;]+@[^\s@,;]+\.[^\s@,;]+$/.test(mail)) {
throw new Error((index + 2) + '行目の名前と宛先を確認してください。');
}
const key = mail.toLowerCase();
if (seen.has(key)) throw new Error('未送信の宛先が重複しています。');
seen.add(key);
pending.push({row: index + 2, name: name, mail: mail, original: row.slice()});
});
if (!DRY_RUN && pending.length > MailApp.getRemainingDailyQuota()) {
throw new Error('残りの送信枠が足りません。今回は送信していません。');
}
pending.forEach(function (item) {
const subject = 'ご案内';
const body = item.name + ' 様\n\nお世話になっております。';
if (DRY_RUN) {
console.log(JSON.stringify({row: item.row, to: item.mail, subject: subject, body: body}));
return;
}
const current = sheet.getRange(item.row, 1, 1, 3);
if (sheet.getLastRow() !== lastRow || current.getFormulas()[0].some(Boolean) ||
JSON.stringify(current.getValues()[0]) !== JSON.stringify(item.original)) {
throw new Error('確認後に行が変わりました。送信を停止します。');
}
if (MailApp.getRemainingDailyQuota() < 1) throw new Error('残りの送信枠がありません。');
const state = sheet.getRange(item.row, 3);
state.setValue('送信中');
SpreadsheetApp.flush();
const beforeSend = current.getValues()[0];
if (current.getFormulas()[0].some(Boolean) || beforeSend[0] !== item.original[0] ||
beforeSend[1] !== item.original[1] || beforeSend[2] !== '送信中') {
throw new Error('送信準備中に行が変わりました。結果を確認してください。');
}
MailApp.sendEmail(item.mail, subject, body);
const afterSend = current.getValues()[0];
if (current.getFormulas()[0].some(Boolean) || afterSend[0] !== item.original[0] ||
afterSend[1] !== item.original[1] || afterSend[2] !== '送信中') {
throw new Error('送信後に行が変わりました。再送せず履歴を確認してください。');
}
state.setValue('送信済み');
SpreadsheetApp.flush();
});
} finally {
lock.releaseLock();
}
}表の準備と送信前のプレビュー
- 「送信練習」シートを作り、1行目にA列「名前」、B列「メールアドレス」、C列「状態」と入力します。この例は最大10データ行に限定します。A:Cに数式や結合セルを置かず、実行中は並べ替え・行の挿入削除・共同編集をしないでください。
- 2行目に自分の名前と自分のメールアドレスを入れ、C列は空にします。
- スプレッドシートの「拡張機能」→「Apps Script」にコードを保存します。
- DRY_RUNがtrueのままsendMailsを実行し、ログに出る宛先・件名・本文を確認します。
- 自分宛の1行で確認できたらDRY_RUNをfalseにして実行し、受信とC列の「送信済み」を確認します。
プレビューはメールを送らず、状態も変更しません。
ログには宛先が表示されるため、共有やスクリーンショット掲載の前に個人情報を除いてください。
テストは、自分のアドレスだけを入れて、先に試してください。
1日の上限
| 項目 | 無料アカウント | Google Workspace |
|---|---|---|
| メールの受信者数/日 | 100 | 1,500 |
| ドメイン内の宛先/日 | 100 | 2,000 |
上限は、メールの通数ではなく、受信者の人数で数えられます。
送る前に、残りの枠を確かめられます。
Logger.log(MailApp.getRemainingDailyQuota());一斉送信は、送り先の同意があるものに限ってください。
Gmail側の、1通あたりの宛先数の上限は、この記事では確認していません。
まとめ
- 送信だけなら MailApp
- 上限は受信者数。無料は100、Workspaceは1,500が目安
- 本番の前に、残りの枠と自分宛のテストを確かめる
参考:Google Apps Script「Mail Service」「Gmail Service」「Quotas for Google Services」(2026年9月30日確認)。
再実行と途中停止の扱い
空の行と状態が入った行は処理しません。
未送信行の宛先重複や入力不足は、送信を始める前に止めます。送信済み行を含めた宛先重複は検出しないため、同じ宛先の新しい行を追加すれば再び送信対象になります。
宛先の正規表現は入力ミスを見つける簡易チェックで、メールアドレスの存在や配信成功は保証しません。
送信する直前に「送信中」を保存し、sendEmailが戻った行を「送信済み」にします。
エラーや時間切れで「送信中」が残った行は、送信結果が不明なため、自動では再送しません。
送信履歴や受信側で結果を確認してから、再送が必要な行だけC列を空に戻してください。
「送信済み」は送信処理が戻った記録で、相手の受信箱への到着確認ではありません。送信前後に行の内容を再確認しますが、確認直後の編集や別プロジェクトからの変更を原子的に防ぐものではありません。行が変わったというエラーでは、状態欄を消して再実行せず、送信履歴と各行を照合してください。
停止するときはDRY_RUNをtrueに戻し、設定した時間主導トリガーがあれば対象だけ削除します。
送信済みメールは、シートやスクリプトを戻しても取り消せません。
確認した範囲と公式資料
2026年10月2日の検証記録を基に、2026年10月23日に最大行数・見出し・数式/結合セル・送信前後の入力再確認を補いました。
今回の改訂コードはローカルの構文検査と模擬サービスによる分岐テストで確認しています。実際のメール送信とは区別してください。
GAS上の認可・トリガー発火・同時実行・実メール送信は未検証です。
MailAppの公式リファレンス / Apps Scriptの割り当て
関連する手順:GASのLockServiceで同時実行を防ぐ|3種類のロックと書き方
よくある質問:GASでGmailを一斉送信するときのチェックリスト
GASでスプレッドシートからメールを送るには、何を使いますか?
MailAppかGmailAppを使います。送信だけなら、必要な権限が小さいMailAppが向いています。GmailAppは、送信に加えて、Gmailの読み書きもできますが、権限が広くなります。
1日に送れる上限は、どのくらいですか?
Google公式の割り当てページ(最終更新2026年9月3日)の記載として、メールの受信者数は、無料アカウントが100、Google Workspaceが1,500と説明しています。上限は、メールの通数ではなく、受信者の人数で数えられます。最新の数値は、公式ページで確認してください。
残りの送信枠は、確認できますか?
MailApp.getRemainingDailyQuota()で、確認できます。本番の前に、残りの枠と自分宛のテストを確かめてください。
本番の前に、どう試せばよいですか?
DRY_RUNがtrueのまま実行し、ログに出る宛先・件名・本文を確認します。次に、自分のアドレスだけを入れて、自分宛の1行で試します。ログには宛先が表示されるため、共有やスクリーンショット掲載の前に個人情報を除いてください。
エラーで途中で止まったときは、どうしますか?
エラーや時間切れで「送信中」が残った行は、送信結果が不明なため、自動では再送しません。送信履歴や受信側で結果を確認してから、再送が必要な行だけ、C列を空に戻します。
送信したメールは、取り消せますか?
取り消せません。送信済みメールは、シートやスクリプトを戻しても取り消せません。また、「送信済み」は、送信処理が戻った記録で、相手の受信箱への到着確認ではありません。
誰にでも、一斉送信してよいですか?
一斉送信は、送り先の同意があるものに限ってください。
