GASで宛先ごとに名前や本文の一部を変えてメールを一括送信したい
■ 先に結論
Apps Scriptで、1行ごとに {名前} などを差し替えて送ります。
「送信済み」に日時を書いた行は再実行で飛ばします。
- シートに宛先と送信済みの列を作る
- コードを貼り、自分宛てに1通テスト
- 下書き手で送った行に日時を記入
- すぐ送る送って日時を記入
- 送信は取り消せない前提で進める
- 送信済み列が日時で埋まれば完了
※2026年10月時点の公式ドキュメントに基づきます。

1一覧と送信済み列を作る
{名前}様佐藤様
このコードでは {見出し} を同じ列の値に置換
1行目に「宛先」「名前」「本文」「送信済み」の見出しを並べ、1人1行で入れます。
2コードを貼って自分宛てに試す
- 「拡張機能」 → 「Apps Script」を開く
- 下のコードに置き換え、1〜4行目を書き換えて保存
- 一覧のシートを開いたまま、プルダウンで sendAll を選び「実行」
- 許可して、自分に届いた1通を確かめる
const MODE = `test`; // test / draft / send
const ME = `[email protected]`;
const SUBJECT = `{名前}様 ご案内`;
const BODY = `{名前}様\n\n{本文}`;
function sendAll() {
const sheet = SpreadsheetApp.getActiveSheet();
const rows = sheet.getDataRange().getDisplayValues();
const head = rows.shift();
if (!head.includes(`宛先`) || !head.includes(`送信済み`)) throw new Error(`見出しを確認`);
let row = 1;
for (const r of rows) {
row++;
const v = new Map(), cells = r.values();
head.forEach((h) => v.set(h, cells.next().value));
if (!v.get(`宛先`) || v.get(`送信済み`)) continue;
const fill = (t) => t.replace(/\{(.+?)\}/g, (m, k) => v.get(k) ?? m);
const sub = fill(SUBJECT), body = fill(BODY);
if (MODE === `test`) return GmailApp.sendEmail(ME, sub, body);
if (MODE === `send`) {
if (!MailApp.getRemainingDailyQuota()) throw new Error(`上限です`);
GmailApp.sendEmail(v.get(`宛先`), sub, body);
} else GmailApp.createDraft(v.get(`宛先`), sub, body);
sheet.getRange(row, head.indexOf(`送信済み`) + 1).setValue(MODE === `send` ? new Date() : `下書き`);
SpreadsheetApp.flush();
}
}
「このアプリは確認されていません」と出たら、「詳細」から「(プロジェクト名)に移動(安全ではありません)」を選びます。Workspace では管理者の承認が要ることもあります。自分で貼ったコード以外は許可しないでください。
出典: Class GmailApp / Gmail と Google スプレッドシートでメールへの差し込みを作成する / チームの休暇カレンダーを作成する
3下書きか送信に切り替える
draft
- 全員分を下書きに
- 列に「下書き」
send
- そのまま送る
- 列に日時
送信は取り消せない前提で、先に test で確かめます。手で送った下書きの行は、列を日時に書き換えます。send の前に、Gmailの送信済みに無い行だけ「下書き」と下書きを消します。
1日の受信者数上限は、一般ユーザー向けで100、Google Workspace で1,500です。上限で止まったら、最初のリクエストから24時間後に再実行します。6分で打ち切られたら、送信済みが空の最初の行の相手がGmailの送信済みにあるか確かめ、あればその行の送信済み列に日時を手で入れてから再実行します。
出典: Google サービスの割り当て