【GAS】スプレッドシートからメールを一斉送信する方法|安全なメールマージ

スプレッドシートから、宛先ごとに名前や本文を変えてメールを一斉送信できますか?

はい。送信リスト、テンプレート、Google Apps Scriptの3つを用意すればできます。この記事では、送信上限の事前確認、送信済み管理、二重実行防止を含むコードを使います。

宛先ごとに「○○さん」のように名前や用件を差し込む仕組みを、メールマージと呼びます。数件の連絡を繰り返し送る業務を効率化できます。

最初から本番の宛先へ送らないでください。
まず宛先を自分のメールアドレス1件だけにし、件名、差し込み文字、改行、差出人を確認してから本番送信に進みます。

目次

メールマージの仕組み

作るものは、スプレッドシート内の「送信リスト」シートと「テンプレート」シート、そしてそのファイルに紐付くApps Scriptです。

要素役割
送信リスト名前、メールアドレス、件名、個別文、送信状態を管理
テンプレートすべての宛先に共通する本文を管理
Apps Script各行を読み込み、文字を差し込んで送信

MailAppを使う理由

Apps Scriptにはメール送信用の MailApp と、Gmailのスレッドや下書きも操作できる GmailApp があります。今回は送信だけが目的のため、Gmailの受信トレイへアクセスせず、再認証が起きにくい MailApp を使います。

送信前に知っておきたい上限

Apps Scriptのメール送信には、アカウント種別ごとの日次宛先数上限があります。Google公式表の現行値は個人向けアカウントが1日100宛先、Google Workspaceが1日1,500宛先ですが、上限は変更される場合があります。

記事のコードは MailApp.getRemainingDailyQuota() で実行時の残り宛先数を取得し、足りなければ送信せず停止します。最新値はGoogle公式のApps Script割当量で確認できます。

スプレッドシートの準備

送信リストシートを作る

シート名を「送信リスト」にし、1行目へ次の5つの見出しを入力します。表記はコードが探す文字と合わせるため、変えずに使ってください。

名前メールアドレス件名内容送信状態
山田太郎taro@example.comご案内8月の日程は10日です。
佐藤花子hanako@example.comご案内8月の日程は12日です。
名前、メールアドレス、件名、内容を入力した送信リスト

「送信状態」は最初は空欄にします。送信に成功するとコードが「送信済み」と記録し、次回以降はその行をスキップします。

テンプレートシートを作る

別のシートを追加し、シート名を「テンプレート」にします。A1セルへ共通本文を入力し、名前を入れる場所に {{name}}、個別の内容を入れる場所に {{message}} と記載します。

{{name}}さん

お世話になっております。

{{message}}

どうぞよろしくお願いいたします。
名前と個別内容の差し込み位置を記載したテンプレート

Apps Scriptを起動してコードを記述

スプレッドシートに紐付くスクリプトを開く

  1. 1スプレッドシートの「拡張機能」を開きます。
  2. 2「Apps Script」を選びます。
  3. 3エディタの Code.gs に次のコードを貼り付けます。
  4. 4プロジェクト名を入力し、保存します。
スプレッドシートからApps Scriptエディタを開く操作
function sendMailMerge() {
  const gate = LockService.getDocumentLock();
  if (!gate.tryLock(5000)) {
    SpreadsheetApp.getUi().alert('ほかの送信処理が実行中です。');
    return;
  }

  try {
    const activeBook = SpreadsheetApp.getActiveSpreadsheet();
    const listSheet = activeBook.getSheetByName('送信リスト');
    const templateSheet = activeBook.getSheetByName('テンプレート');

    if (!listSheet || !templateSheet) {
      throw new Error('シート名を確認してください。');
    }

    const values = listSheet.getDataRange().getDisplayValues();
    if (values.length < 2) {
      throw new Error('送信リストに宛先がありません。');
    }

    const labels = values.shift();
    const namePos = labels.indexOf('名前');
    const mailPos = labels.indexOf('メールアドレス');
    const subjectPos = labels.indexOf('件名');
    const messagePos = labels.indexOf('内容');
    const statePos = labels.indexOf('送信状態');
    const neededPos = [namePos, mailPos, subjectPos, messagePos, statePos];

    if (neededPos.some(function (pos) { return pos < 0; })) {
      throw new Error('1行目の見出しを確認してください。');
    }

    const templateText = templateSheet.getRange('A1').getDisplayValue();
    const targetRows = [];

    for (let pos = 0; pos < values.length; pos++) {
      const line = values[pos];
      if (line[mailPos] && line[statePos] !== '送信済み') {
        targetRows.push(pos);
      }
    }

    if (!targetRows.length) {
      SpreadsheetApp.getUi().alert('未送信の宛先はありません。');
      return;
    }

    const quota = MailApp.getRemainingDailyQuota();
    if (targetRows.length > quota) {
      throw new Error('本日の残り宛先数は' + quota + '件です。');
    }

    const ui = SpreadsheetApp.getUi();
    const answer = ui.alert(
      '送信前の確認',
      targetRows.length + '件のメールを送信します。',
      ui.ButtonSet.OK_CANCEL
    );

    if (answer !== ui.Button.OK) {
      return;
    }

    let doneNum = 0;
    for (let pos = 0; pos < targetRows.length; pos++) {
      const dataPos = targetRows[pos];
      const line = values[dataPos];
      const name = line[namePos];
      const mail = line[mailPos];
      const subject = line[subjectPos];
      const message = line[messagePos];
      const body = templateText
        .replaceAll('{{name}}', name)
        .replaceAll('{{message}}', message);

      MailApp.sendEmail(mail, subject, body);
      listSheet.getRange(dataPos + 2, statePos + 1).setValue('送信済み');
      SpreadsheetApp.flush();
      doneNum++;
    }

    ui.alert(doneNum + '件のメールを送信しました。');
  } finally {
    gate.releaseLock();
  }
}
Apps Scriptエディタにメール送信コードを記述した状態

コードが行っていること

  • 5つの見出し位置を名前で探す
  • メールアドレスがあり、「送信済み」ではない行だけを対象にする
  • 本日の残り宛先数より多ければ実行を止める
  • 送信件数をダイアログで確認する
  • 送信後に「送信済み」を記録し、再実行時の重複送信を防ぐ
  • 連打や複数人の同時実行をドキュメントロックで防ぐ

MailAppの公式リファレンスには、CC、BCC、返信先、HTML本文、添付ファイルなどの追加設定も記載されています。

メール送信ボタンの設置

  1. STEP1
    図形を作る

    スプレッドシートの「挿入」から「図形描画」を開き、図形と「メール送信」などの文字を組み合わせて保存します。

    スプレッドシートの挿入メニューから図形描画を開く操作
    メール送信用の図形ボタンを作る画面
  2. STEP2
    スクリプトを割り当てる

    図形をクリックし、右上のメニューから「スクリプトを割り当て」を選びます。関数名 sendMailMerge括弧なしで入力します。

    図形ボタンのメニューからスクリプトの割り当てを開く操作
    スクリプト割り当て画面にsendMailMergeを入力した状態

Google公式仕様では、図形や画像へ割り当てたスクリプトはWebブラウザでクリックしたときだけ実行されます。スマートフォン版Googleスプレッドではボタンとして動作しません。詳細はGoogle公式のカスタムメニュ解説を確認してください。

初回認証とテスト送信

初回はスクリプトを承認する

メール送信にはGoogleアカウントの承認が必要です。最初の実行時は承認画面が表示されるため、このスプレッドシートとスクリプトを作成したGoogleアカウントを選び、表示内容を確認して進めます。

承認画面の文言や順番はGoogle側の変更で変わるため、画面の色やボタン位置ではなく、自分で作ったプロジェクトか、送信権限の理由は適切かを確認してください。承認に関する現行仕様はGoogle公式の承認ガイドで確認できます。

自分宛ての1件でテストする

  1. 1送信リストを自分のメールアドレス1件だけにします。
  2. 2「送信状態」を空欄にし、図形ボタンをクリックします。
  3. 3確認ダイアログの件数が1件であることを確認し、実行します。
  4. 4受信したメールとGmailの送信済みトレイで、件名、本文、差出人を確認します。
  5. 5シートの「送信状態」が「送信済み」になったことを確認します。
スプレッドシートの内容を差し込んだメールがGmailの送信済みに表示された状態

テストが成功したら本番データを追加し、件数を再確認して実行します。受信者の同意を得ていない宣伝メールや、送信元を明らかにしない一方的な送信には使わないでください。

うまく送信できないとき

「シート名」または「見出し」のエラーが出る

シート名は「送信リスト」と「テンプレート」、1行目の見出しは「名前」「メールアドレス」「件名」「内容」「送信状態」にします。前後の空白や似た文字が入っていないかも確認します。

送信可能な残り宛先数が足りない

エラーに表示された残り宛先数以下に分割して実行するか、割当量がリセットされるのを待ちます。複数のアカウントに分けて上限を回避する運用はしません。

送信済みの行をもう一度送りたい

再送したい行の「送信状態」を空欄に戻すと再び対象になります。ただし、ほかの未送信行も同時に対象になるため、確認ダイアログの件数を必ず確認してください。

まとめ

  • 送信リストとテンプレートを別シートで用意する
  • 送信だけなら、権限範囲の狭い MailApp を使う
  • 送信済み列と実行ロックで重複送信を防ぐ
  • 実行前に残り宛先数と今回の送信件数を確認する
  • 本番送信前に自分宛て1件テストする

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次