【コピペで動く】スプレッドシートからGmailを一括送信する方法|GASで差し込みメールを自動化

スポンサーリンク

スプレッドシートに溜まった顧客リストや社員名簿を見ながら、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 + '件'
  );
}

実行手順

  1. スクリプトエディタ上部の関数選択で sendBulkEmail を選択
  2. 「実行」ボタンをクリック
  3. 初回は権限承認の画面が出るので、「権限を確認」→「(自分のアカウント)」→「詳細」→「(プロジェクト名)(安全ではないページ)に移動」→「許可」の順に進める
  4. 完了アラートが出れば成功

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ファイルや