スプレッドシートに溜まった顧客リストや社員名簿を見ながら、Gmailで1通ずつ宛名を変えて送信していませんか。10通ならまだしも、50通・100通になると本当に消耗しますよね。実はその作業、Google Apps Script(GAS)を使えば1クリックで自動化できます。Word差し込み印刷のメール版を、無料のGmailとスプレッドシートだけで実現できるのです。この記事では、コピペで動く完成コード3パターン(基本/HTMLメール/添付ファイル付き)と、誤送信を防ぐテストモード・送信上限の対策まで、実務で使える形でまとめました。
スプレッドシートからGmailを一括送信するとは?|GASで差し込みメールを自動化する仕組み
スプレッドシートからGmailを一括送信する仕組みは、シンプルに言えば「メールアドレス一覧をスプレッドシートに用意し、GASで1行ずつ読み込んでGmail経由で送る」というものです。GAS(Google Apps Script)はGoogleが提供する無料のスクリプト環境で、JavaScriptに似た言語で書きます。
差し込み印刷と同じ発想で、本文に {{name}}様 のようなプレースホルダーを書いておき、スプレッドシートの「名前列」の値で置換します。これで「○○様、いつもお世話になっております」のように個別の宛名を入れた状態で、100通でも500通でもまとめて送信できます。
NOTE: GASは追加費用ゼロで使えます
Googleアカウントを持っていれば、GASは無料で利用できます。インストール不要で、ブラウザ上のエディタですぐに書き始められます。Google Apps Scriptの基本操作はGAS入門記事で解説しているので、初めて触る方はそちらから読んでください。
こんなシーンで活躍します
- 取引先50社へ請求書送付の案内メール(添付PDFは行ごとに変える)
- セミナー申込者100名へ参加URLとパスワードを個別送信
- 社内メンバー30名へ年末挨拶メール(部署名と氏名を差し込み)
- 顧客リストにアンケート依頼を一斉送信
- 退会フォーム提出者にお礼メールを自動返信
メール配信ツールを契約せず、今あるスプレッドシートとGmailだけで完結するのが最大のメリットです。
一括送信を始める前の準備|スプレッドシートのレイアウトとGmail送信枠
まずは送信元データを準備します。スプレッドシートのレイアウトと、Gmailの送信上限を必ず先に確認してください。
スプレッドシートのレイアウト例
A列〜E列に以下のヘッダーを置きます。1行目がヘッダー、2行目以降がデータ行です。
| A: メールアドレス | B: 名前 | C: 会社名 | D: 件名差し込み | E: 送信ステータス |
|---|---|---|---|---|
| sample01@example.com | 山田太郎 | 株式会社サンプル | 4月度ご請求書 | (空欄) |
| sample02@example.com | 鈴木花子 | サンプル商事 | 4月度ご請求書 | (空欄) |
E列の「送信ステータス」は、送信成功時に「済」と書き込む列です。途中でエラーになっても、再実行時にE列が空欄の行だけ送信できるので、重複送信を防げます。
Gmailの送信上限を必ず確認する
WARNING: Gmailには1日あたりの送信上限があります
通常のGmail(@gmail.com 無料アカウント)は1日100通まで、Google Workspaceの有料アカウントは1日1,500通までです。上限を超えるとアカウントが一時的にロックされ、最大24時間メール送信ができなくなります。
| アカウント種別 | 1日の送信数上限 |
|---|---|
| 通常のGmail(無料) | 100通 |
| Google Workspace(有料) | 1,500通 |
| Workspace(試用版) | 500通 |
リセットは前回送信から24時間後で、暦日(0時リセット)ではない点に注意してください。100通を超える送信が必要な場合は、Workspaceの導入か、メール配信専用ツールへの切り替えを検討しましょう。
スクリプトエディタを開く
スプレッドシートのメニューから「拡張機能」→「Apps Script」をクリックします。新しいタブでスクリプトエディタが開きます。初回は無題のプロジェクトが作成されるので、左上のプロジェクト名を分かりやすい名前(例: gmail-bulk-send)に変更しておきましょう。
【レシピ1】基本の差し込みメール一括送信(コピペで動くGAS)
それではコードを書いていきます。最初は基本のテキストメール一括送信です。スプレッドシートの「名前」「会社名」を本文に差し込んで送信します。
コード本体
スクリプトエディタの初期コード(function myFunction() { })をすべて消して、以下を貼り付けます。
// --- 基本: テキストメールの一括送信 ---
function sendBulkEmail() {
// --- 設定値 ---
const SHEET_NAME = 'シート1'; // 対象シート名
const TEST_MODE = true; // true=自分のみに送信(テスト用)
const TEST_EMAIL = 'your-email@example.com'; // テスト用の自分のアドレス
const SENDER_NAME = '山田 太郎'; // 差出人表示名
// --- メールテンプレート ---
const subjectTemplate = '{{subject}}のご案内';
const bodyTemplate = `{{company}}
{{name}}様
いつも大変お世話になっております。
山田です。
{{subject}}についてご連絡いたします。
詳細は添付の資料をご確認ください。
引き続きよろしくお願いいたします。`;
// --- スプレッドシートからデータ取得 ---
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME);
const values = sheet.getDataRange().getValues(); // 全データを2次元配列で取得
const header = values[0]; // 1行目はヘッダー
const rows = values.slice(1); // 2行目以降がデータ
// --- 残り送信可能数チェック ---
const quota = MailApp.getRemainingDailyQuota();
if (quota < rows.length) {
throw new Error('送信可能数が不足: 残り' + quota + '通 / 必要' + rows.length + '通');
}
// --- 行ごとに送信 ---
let successCount = 0; // 成功カウンター
let errorCount = 0; // 失敗カウンター
rows.forEach((row, i) => {
const email = row[0]; // A列: メールアドレス
const name = row[1]; // B列: 名前
const company = row[2]; // C列: 会社名
const subject = row[3]; // D列: 件名差し込み
const status = row[4]; // E列: 送信ステータス
// --- 既に送信済みの行はスキップ ---
if (status === '済') return;
// --- メールアドレスが空の行はスキップ ---
if (!email) return;
// --- テンプレートを差し込み置換 ---
const finalSubject = subjectTemplate.replace(/{{subject}}/g, subject);
const finalBody = bodyTemplate
.replace(/{{name}}/g, name)
.replace(/{{company}}/g, company)
.replace(/{{subject}}/g, subject);
// --- テストモードなら自分宛に送信、本番なら本人宛 ---
const recipient = TEST_MODE ? TEST_EMAIL : email;
try {
MailApp.sendEmail(recipient, finalSubject, finalBody, {
name: SENDER_NAME
});
// --- 送信成功時はE列に「済」を書き込み ---
if (!TEST_MODE) {
sheet.getRange(i + 2, 5).setValue('済');
}
successCount++;
} catch (e) {
// --- 失敗時はE列にエラー内容を記録 ---
sheet.getRange(i + 2, 5).setValue('エラー: ' + e.message);
errorCount++;
}
});
// --- 完了メッセージ ---
const mode = TEST_MODE ? 'テスト' : '本番';
SpreadsheetApp.getUi().alert(
mode + '送信完了n成功: ' + successCount + '件 / 失敗: ' + errorCount + '件'
);
}
実行手順
- スクリプトエディタ上部の関数選択で
sendBulkEmailを選択 - 「実行」ボタンをクリック
- 初回は権限承認の画面が出るので、「権限を確認」→「(自分のアカウント)」→「詳細」→「(プロジェクト名)(安全ではないページ)に移動」→「許可」の順に進める
- 完了アラートが出れば成功
WARNING: 初回は必ず TEST_MODE = true で実行してください
いきなり本番送信すると誤送信のリスクが高いです。最初はTEST_MODE = trueのまま自分のアドレス宛に何通か送って、本文と件名の差し込みが正しく動くか確認しましょう。問題なければTEST_MODE = falseに変更して本番実行します。
コードの読み解きポイント
sheet.getDataRange().getValues()でシート全体を2次元配列にして取得values.slice(1)で1行目(ヘッダー)を除外replace(/{{name}}/g, name)のgフラグは「全置換」の意味。同じプレースホルダーが複数回出てきても全部置換されるMailApp.sendEmail()の第4引数optionsで差出人表示名を指定- 行番号は
i + 2(配列インデックス0始まり + ヘッダー行1分)
【レシピ2】HTMLメール(装飾付き)で一括送信する
太字や色付き文字、表組みを入れたHTMLメールも、htmlBody オプションを使えば送信できます。請求書の合計金額を強調したい、注意事項を赤文字にしたい、といったケースで便利です。
// --- HTMLメールの一括送信 ---
function sendBulkHtmlEmail() {
const SHEET_NAME = 'シート1';
const TEST_MODE = true;
const TEST_EMAIL = 'your-email@example.com';
const SENDER_NAME = '山田 太郎';
const subjectTemplate = '【重要】{{subject}}のご案内';
// --- HTML本文テンプレート ---
const htmlTemplate = `
<p>{{company}}<br>{{name}}様</p>
<p>いつも大変お世話になっております。<br>山田です。</p>
<p>{{subject}}についてご連絡いたします。</p>
<table style="border-collapse:collapse;border:1px solid #ccc;">
<tr style="background:#f5f5f5;">
<th style="padding:8px;border:1px solid #ccc;">項目</th>
<th style="padding:8px;border:1px solid #ccc;">内容</th>
</tr>
<tr>
<td style="padding:8px;border:1px solid #ccc;">対応期限</td>
<td style="padding:8px;border:1px solid #ccc;color:#c00;"><strong>5月20日(火)まで</strong></td>
</tr>
</table>
<p>ご不明点がございましたら、本メールに返信ください。</p>
<p>引き続きよろしくお願いいたします。</p>
`;
// --- プレーンテキスト版(HTML非対応クライアント用) ---
const plainTemplate = `{{company}}
{{name}}様
いつも大変お世話になっております。
山田です。
{{subject}}についてご連絡いたします。
対応期限: 5月20日(火)まで
ご不明点がございましたら、本メールに返信ください。
引き続きよろしくお願いいたします。`;
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME);
const rows = sheet.getDataRange().getValues().slice(1);
let successCount = 0; // 成功カウンター
rows.forEach((row, i) => {
const email = row[0]; // A列: メールアドレス
const name = row[1]; // B列: 名前
const company = row[2]; // C列: 会社名
const subject = row[3]; // D列: 件名差し込み
const status = row[4]; // E列: 送信ステータス
if (status === '済' || !email) return;
const finalSubject = subjectTemplate.replace(/{{subject}}/g, subject);
const finalHtml = htmlTemplate
.replace(/{{name}}/g, name)
.replace(/{{company}}/g, company)
.replace(/{{subject}}/g, subject);
const finalPlain = plainTemplate
.replace(/{{name}}/g, name)
.replace(/{{company}}/g, company)
.replace(/{{subject}}/g, subject);
const recipient = TEST_MODE ? TEST_EMAIL : email;
MailApp.sendEmail(recipient, finalSubject, finalPlain, {
name: SENDER_NAME,
htmlBody: finalHtml
});
if (!TEST_MODE) sheet.getRange(i + 2, 5).setValue('済');
successCount++;
});
SpreadsheetApp.getUi().alert('HTML送信完了: ' + successCount + '件');
}
TIP: HTMLメールはインラインCSSのみ使う
HTMLメールでは、外部CSSファイルやタグ内のクラス指定が効かないクライアントが多いです。色や枠線などのスタイルは、すべて要素のstyle属性に直接書く(インラインCSS)のが鉄則です。
NOTE: スパム判定を避けるコツ
HTMLメールは過度な装飾・大量の画像・リンク多すぎでスパム判定されやすくなります。本文内のリンクは2〜3個までに抑え、画像はロゴ程度にとどめましょう。件名に「【無料】」「【限定】」といった煽り文句を多用するのも避けてください。
【レシピ3】PDF・画像を添付ファイルとして一括送信する
請求書PDFを行ごとに別ファイルで添付したい、といった要望もよくあります。Google Driveに保存したファイルを DriveApp 経由で取得して添付します。
準備: スプレッドシートに「添付ファイルID列」を追加
F列に「添付ファイルID」列を追加し、Google DriveのファイルIDを各行に書きます。ファイルIDはDriveでファイルを開いたときのURL https://drive.google.com/file/d/{ファイルID}/view から取得できます。
| A: メール | B: 名前 | C: 会社 | D: 件名 | E: ステータス | F: ファイルID |
|---|---|---|---|---|---|
| sample01@... | 山田太郎 | サンプル | 4月度請求書 | (空欄) | 1AbCdEf... |
コード本体
// --- 添付ファイル付きの一括送信 ---
function sendBulkEmailWithAttachment() {
const SHEET_NAME = 'シート1';
const TEST_MODE = true;
const TEST_EMAIL = 'your-email@example.com';
const SENDER_NAME = '山田 太郎';
const subjectTemplate = '{{subject}}(請求書添付)';
const bodyTemplate = `{{company}}
{{name}}様
いつもお世話になっております。山田です。
{{subject}}を添付にてお送りいたします。
ご確認のほどよろしくお願いいたします。`;
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME);
const rows = sheet.getDataRange().getValues().slice(1);
let successCount = 0; // 成功カウンター
rows.forEach((row, i) => {
const email = row[0]; // A列: メールアドレス
const name = row[1]; // B列: 名前
const company = row[2]; // C列: 会社名
const subject = row[3]; // D列: 件名差し込み
const status = row[4]; // E列: 送信ステータス
const fileId = row[5]; // F列: 添付ファイルID
if (status === '済' || !email) return;
// --- 添付ファイルをDriveから取得 ---
let attachmentBlob = null;
if (fileId) {
try {
attachmentBlob = DriveApp.getFileById(fileId).getBlob();
} catch (e) {
sheet.getRange(i + 2, 5).setValue('エラー: ファイルID不正');
return;
}
}
const finalSubject = subjectTemplate.replace(/{{subject}}/g, subject);
const finalBody = bodyTemplate
.replace(/{{name}}/g, name)
.replace(/{{company}}/g, company)
.replace(/{{subject}}/g, subject);
const recipient = TEST_MODE ? TEST_EMAIL : email;
const options = { name: SENDER_NAME };
if (attachmentBlob) options.attachments = [attachmentBlob];
try {
MailApp.sendEmail(recipient, finalSubject, finalBody, options);
if (!TEST_MODE) sheet.getRange(i + 2, 5).setValue('済');
successCount++;
} catch (e) {
sheet.getRange(i + 2, 5).setValue('エラー: ' + e.message);
}
});
SpreadsheetApp.getUi().alert('添付付き送信完了: ' + successCount + '件');
}
TIP: 添付ファイルの合計サイズは25MBまで
Gmailの仕様で、添付ファイルの合計サイズは1通あたり25MB以内です。これを超える場合はGoogle Driveのリンク共有を使い、本文に共有URLを差し込む方式が安全です。DriveApp.getFileById(id).getUrl()でファイルURLを取得できます。
NOTE: スプレッドシート自体をPDF化して添付する場合
別シートに作った請求書テーブルをPDFにして添付したい場合は、DriveApp.getFileById(spreadsheetId).getAs('application/pdf')でPDF Blobを生成できます。スプレッドシートIDはシートのURLから取得します。
送信前のテスト方法と誤送信を防ぐ4つのコツ
一括送信は便利ですが、誤送信したときのダメージも大きいです。送信ボタンを押す前に、必ず以下の4つを実施しましょう。
コツ1: TEST_MODE で自分宛に送信して確認する
レシピ1〜3のコードはすべて TEST_MODE = true で動作確認できる構造になっています。最初は必ず自分のアドレスにだけ送信し、件名・本文の差し込みが正しいか、添付ファイルが付いているかを目視確認してください。
コツ2: 送信件数を絞ってから本番実行する
スプレッドシートのデータが100行ある場合、いきなり全部送信せず、最初の3〜5行だけ残して他は別シートに退避させ、少数で本番実行→問題なければ残りを実行、という段階的なやり方が安全です。
コツ3: 送信前に getRemainingDailyQuota() で残数を確認
レシピ1のコードに含めてある通り、送信前に残り送信可能数をチェックします。これがないと、80通目で上限に到達して残り20通が未送信のまま停止する、という事故が起きます。
const quota = MailApp.getRemainingDailyQuota();
console.log('残り送信可能数: ' + quota);
コツ4: 送信ステータス列で重複送信を防ぐ
E列の「送信ステータス」に「済」を書き込む仕組みは、重複送信防止のためです。途中でブラウザが落ちたり、コードがエラーで停止したりしても、再実行時に「済」の行はスキップされるので安全です。
WARNING: BCC欄に入れる安易な一斉送信は厳禁
「Gmailの To 欄に複数アドレス」「BCCに大量アドレス」といったやり方は、相手のメールアドレスが他の受信者に見えてしまう個人情報漏洩リスクがあります。一括送信は必ずGAS経由で1通ずつ個別送信してください。
BCC一斉送信とGAS差し込み送信の違い・使い分け
そもそも「Gmail BCCで全員に送ればいいのでは?」と思った方もいるかもしれません。両者の違いを表で整理します。
| 項目 | BCC一斉送信 | GAS差し込み送信 |
|---|---|---|
| 個別の宛名差し込み | できない | できる({{name}}様 等) |
| 送信先のリスト管理 | 連絡先・アドレス帳 | スプレッドシートで管理 |
| 送信履歴の追跡 | 1通分しか残らない | 各通ごとに履歴 |
| エラー時の個別検知 | できない | try-catchで行ごとに検知 |
| 添付ファイルの個別変更 | できない(全員同じ) | できる(行ごとに別ファイル) |
| 個人情報漏洩リスク | TO/CCに入れると漏洩 | 1通ずつなのでなし |
| 1メールの宛先上限 | 500件まで(Workspace) | 100通/日(無料), 1500通/日(有料) |
ざっくり使い分けると、以下のようになります。
- BCC一斉送信が向くケース: 内容がまったく同じ・宛名差し込み不要・社内メンバー数十名への一斉連絡
- GAS差し込み送信が向くケース: 宛名・会社名・添付ファイルを個別に変えたい・送信履歴を残したい・送信ミスを行ごとに検知したい
社外への請求書送付や顧客向けセミナー案内などは、誤送信リスクと個別性の観点からGAS差し込み送信が安全です。
スプレッドシート×Gmail一括送信でよくあるエラーと対処法
実際にコードを動かしてみて遭遇しやすいエラーをまとめました。
| エラーメッセージ | 原因 | 対処法 |
|---|---|---|
Service invoked too many times: email | 1日の送信上限に到達 | 24時間待つ、またはWorkspaceに切り替え |
Authorization is required | 権限承認が未完了 | スクリプトエディタで「権限を確認」を実施 |
Invalid email: | メールアドレス列に不正な値 | A列の値を確認、空欄行のスキップ処理を追加 |
Cannot find file with id: xxx | DriveApp.getFileById のIDが間違い | F列のファイルIDを再確認、共有設定も確認 |
Cannot read property '0' of undefined | シート名が間違い、またはシートが空 | SHEET_NAME の値を確認 |
Exception: Argument too large: subject | 件名が長すぎ(256文字超) | 件名を短く調整 |
| メールが届かない | スパムフォルダ行き | 件名・本文の煽り文句を減らす、送信元表示名を固定 |
よくある間違い: 「済」の判定で全角と半角が混在
「済」の文字を全角で書いたり、前後にスペースが入ったりすると、判定がうまくいかず重複送信が起きます。コード内で書き込む値と判定する値を完全一致させましょう。心配な場合は if (String(status || '').trim() === '済') return; のように String() でラップしてから .trim() で前後空白を除去すると、空セル(undefined/null)でも安全に判定できます。
よくある間違い: 改行コードの混在
スプレッドシートのセル内改行(Alt+Enter)と、コード内のテンプレート文字列(バッククォート の改行)はどちらも n として扱われますが、Windows環境からコピペしたデータでは rn が混入することがあります。送信されたメールで改行が崩れる場合は、コード冒頭で text.replace(/rn/g, 'n') のように正規化を入れてください。
TIP: Slack通知と組み合わせる
送信完了時にSlackへ自動通知すると、運用効率がさらに上がります。SlackのIncoming Webhookを使った通知方法は、GoogleフォームとGAS連携記事のレシピ2で詳しく解説しています。一括送信の最後に流用できるので、合わせて確認してください。
まとめ|スプレッドシート×GASでメール送信業務を一気に効率化する
スプレッドシートからGmailを一括送信するGASの仕組みを、3パターンのコピペコード(基本/HTMLメール/添付ファイル付き)と実務Tipsで解説しました。重要なポイントを最後にもう一度まとめます。
- スプレッドシートに「メール/名前/会社/件名/ステータス」の5列を用意する
- 本文に
{{name}}等のプレースホルダーを書き、replace()で差し込み置換する - 必ず
TEST_MODE = trueで自分宛に動作確認してから本番実行する - Gmail送信上限は無料100通/日、Workspace 1,500通/日。
getRemainingDailyQuota()で事前チェック - 送信ステータス列で重複送信を防ぎ、try-catchでエラー行を記録する
- HTMLメール・添付ファイルも
options引数で柔軟に対応できる - BCC一斉送信は宛名差し込みできず、TO欄に入れた誤送信で個人情報漏洩リスクあり
- 送信履歴・差し込み・添付ファイル個別変更が必要ならGAS差し込み送信が最適
これで、Word差し込み印刷のメール版が無料で実現できます。GAS自動化シリーズ3部作の最終回として、ぜひ業務に取り入れてみてください。
シリーズ全体を読み返したい方は、入門のGAS入門|スプレッドシート自動化レシピ5選、続編のGoogleフォーム×GASで回答を自動通知・集計する方法も合わせてご覧ください。3記事を組み合わせれば、データ収集(フォーム)→ 自動集計(スプレッドシート+GAS)→ メール送信(一括差し込み)という業務自動化の基本パターンがすべて押さえられます。
