MAGAZINE

ルーターマガジン

JavaScript/Node.js

【GAS】画像や絵文字を含めたメールをGmailで一括送信できるようにする

2026.03.30
Pocket

免責:この記事は2026年3月執筆時点の情報になります。この機能が現在同様に動作するかは、自身でテストを行った上で注意して使用してください。

はじめに

こんにちは。ルーターのmiyakawaです。

DM配信など個人のみに向けたメールを複数人に送信をすること機会がありました。10人程度なら手作業でもいいのですが、100人単位になるとメール送信だけでもたくさんの時間を奪われてしまうでしょう。

そこで個人向けメールの一括送信をする機能が必要でした。送信するメールのコンテンツには、画像や絵文字が含まれているケースになります。

今回はメールの一括送信機能が簡単に利用できて、かつ利用者がどの方に向けて送信するかをスプレッドシートで管理できるようにするためGAS(Google Apps Script)を用いたメール一括送信機能の実装方法を共有いたします。

送信先シートを作成する

はじめに一括送信するための送信先リストを作成します。特にファイル作成箇所にこだわりがないならこちらからスプシを作成し、以下4つの列を追加します。

  • 送信ステータス(未送信・送信成功・送信失敗)
  • 送信者氏名
  • 受信者氏名
  • 送信先メールアドレス

メール送信機能を実装手順

大まかな流れとしては以下の通りです。

  1. HTMLファイルを作成する
  2. HTMLファイルと画像ファイルをGoogle Driveにアップロードする
  3. GASのスクリプトを作成する
  4. スクリプトを実行する

画像や絵文字を表示するにはメールコンテンツをHTMLで作成する必要があります。そのためメール送信用のHTMLファイルを作成します。

送信する予定のメールコンテンツのHTMLファイルは以下の通りです。

<div>{{受信者氏名}}様</div>
<div>こちらはテスト用のメールです。&#x1f602;</div>
<div><img src="cid:testImage"></div>

ここではGAS側で個人名を切り替えできるように{{受信者氏名}}をHTMLに加えています。

次にGASで読み込めるようにGoogle Driveにアップロードしてください。またメール添付画像も必要な場合はGoogle Driveにアップロードしてください。

次にGASに以下のメール送信関数とメール送信メニューを作成します。スプレッドシートからApps Scriptを開いて、以下のJavaScriptをコピペして、かつHTMLファイルや画像ファイルをGASで読み込めるようにFile IDを追加してください。

// --- メール送信関数 ---
function sendEmails() {
  // --- HTMLファイルの取得 ---
  const ui = SpreadsheetApp.getUi();

  let htmlTemplate = '';
  try {
    // File IDと呼ばれるGoogle Driveのファイルリンクに記載されているURLの/d/の次のパスのテキストを代入
    // https://drive.google.com/file/d/1234567890abcdefghij/viewの場合は「1234567890abcdefghij」が対象のパス
    const templateHTMLFileId = ""; // ここにFile IDを追加する
    const templateFile = DriveApp.getFileById(templateHTMLFileId);
    htmlTemplate = templateFile.getBlob().getDataAsString('utf-8');
  } catch (e) {
    ui.alert("HTMLファイルの読み込みに失敗しました。\n" + e.message);
    return; // テンプレートがなければ処理を中断
  }
  // ------------------------------------

  // --- 画像ファイル読み取り ---
  let testImage;
  try {
    // 画像ファイルも同様にFile IDを代入する
    const teplateImageFileId = ""; // ここにFile IDを追加する
    const testImageFile = DriveApp.getFileById(teplateImageFileId);
    testImage = testImageFile.getBlob();
  } catch (e) {
    ui.alert("画像の読み込みに失敗しました。\n" + e.message);
    return; // 画像がなければ中断
  }
  // ------------------------------------

  // 送信先リストのスプシに記載されている内容を列名を含めずに読み取る(ここでは新規作成したスプシのシートを対象にしている)
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("シート1");
  // データが1件もない(ヘッダーのみ)場合はエラーを回避して終了
  if (sheet.getLastRow() < 2) {
    ui.alert("送信対象のデータ(2行目以降)が見つかりません。");
    return;
  }

  const dataRange = sheet.getRange(2, 1, sheet.getLastRow() - 1, sheet.getLastColumn());
  const data = dataRange.getValues();

  // 列名番号に名前を振る
  COLUMN_NUMBERS = {
    status: 1,
    senderName: 2,
    recipientName: 3,
    recipientEmail: 4,
  }

  // メールの題目の設定
  const subject = "メール送信テストです"

  // ヘッダーを除いた行ごとにメールを送信する
  for (let i = 0; i < data.length; i++) {
    const row = data[i];
    // 現在の送信ステータス・送信者氏名・受信者氏名・受信者メールアドレスを取得
    const currentStatus = row[COLUMN_NUMBERS.status - 1];
    const senderName = row[COLUMN_NUMBERS.senderName - 1];
    const recipientName = row[COLUMN_NUMBERS.recipientName - 1];
    const recipientEmail = row[COLUMN_NUMBERS.recipientEmail - 1];

    // 送信ステータスが未送信の場合のみ実行
    if (currentStatus === "未送信") {

      //受信者メールアドレスがない場合は、何もしない
      if (!recipientEmail) {
        continue;
      }

      // テンプレートから読み込んだHTML内のプレースホルダーを置換
      let htmlBody = htmlTemplate.replace(/{{受信者氏名}}/g, recipientName)

      try {
        // メール送信関数、受信者メールアドレス、題目、プレーンテキストメール時のメール本文、他に必要なオプションがある場合はさらに細かく設定可能
        GmailApp.sendEmail(recipientEmail, subject, '', {
          name: senderName, // 送信者氏名
          htmlBody: htmlBody, // メールにて送信するHTMLの内容
          inlineImages: { // HTML内で画像を添付する画像の情報
            testImage: testImage, // // HTML側の cid:testImage と一致させる
          }
        });

        // 送信が成功した場合での送信ステータスを更新
        const currentSheetRow = i + 2;
        sheet.getRange(currentSheetRow, COLUMN_NUMBERS.status).setValue("送信成功");
      } catch (e) {
        // 送信が失敗した場合での送信ステータスを更新
        const currentSheetRow = i + 2;
        sheet.getRange(currentSheetRow, COLUMN_NUMBERS.status).setValue("送信失敗 エラー: " + e.message);
      }
    }
  }
}
// ------------------------------------

// メール送信用のメニューバーを作成する。
function onOpen() {
  SpreadsheetApp.getUi()
      .createMenu('✉️ メール送信')
      .addItem('未送信のメールをすべて送信', 'sendEmails')
      .addToUi();
}

GASにスクリプトを記載すると、メール送信用のメニューバーが表示されるようになります。

「未送信のメールをすべて送信」をクリックすると、承認してくださいと表示されますので全て承認することでメールの一括送信が行われます。

送信ステータスが未送信の方にメール送信を行い、送信が成功した場合は送信成功に、失敗した場合は送信失敗に変わります。

以下、実際に送信されたメールになります。

メールコンテンツに絵文字の追加する方法

GmailAppにてメールコンテンツに絵文字を表示する際は、絵文字のUnicodeをHTMLに記載します。

今回は😂のUnicodeでHTML内に記載しています。

&#x1f602;

これはGmailApp.sendEmailの機能が、Unicode 6.0以降の絵文字の変換に対応できていないため、HTMLファイルに絵文字をそのまま貼り付けて送信すると文字化けが発生してしまいます。そこで絵文字のUnicodeをHTMLに記載することで、絵文字のUnicodeをGmail側で読み取って絵文字に変換してくれるのでこの手法が無難です。

メールコンテンツに画像を追加する

画像は、Google DriveにアップロードしたファイルをGAS側で読み込み、inlineImagesに画像のバイナリ情報を格納することで、メール内に画像を呼び出すことができます。

メールの特定の箇所に画像を呼び出す際はinlineImagesに設定したキー名に一致させたimgタグ

<img src="cid:testImage">

をHTMLに挿入することで、好きな箇所で画像を表示できるようになります。

GASに読み込ませる画像を増やして、inlineImagesにキーをそれぞれ設定することで複数画像を表示できます。

GmailApp.sendEmail(recipientEmail, subject, '', {
  ...
  inlineImages: { // 必要な分だけGoogle Driveから画像を読み込み、キーを設定してメールコンテンツに追加できる
    testImage1: testImage1,
    testImage2: testImage2,
    testImage3: testImage3,
  },
}

おわりに

メールを一括送信することができました。他にもstyle属性を指定することでテキストのレイアウトを変更したメール装飾も可能です。

ただGASのメール送信には制限があり、無料アカウントは1日100件まで、有料アカウント1,500件ですので、この点に関しては注意が必要です。

ぜひみなさんもメールの一括送信で業務時間の効率化を目指してみてはいかがでしょうか。

Pocket

CONTACT

お問い合わせ・ご依頼はこちらから