EmailVerify LogoEmailVerify

Google Forms

Email checker for Google Forms. Verify submitted emails with Apps Script integration.

Google Forms に EmailVerify を統合し、回答が送信されたときに自動的にメールアドレスを検証しましょう。

連携方法

方法最適な用途複雑さ
Apps Script自動検証
Sheets アドオン手動検証
Zapierノーコードワークフロー

方法 1:Google Apps Script

Google Apps Script を使用して自動検証ワークフローを作成します。

ステップ 1:Apps Script プロジェクトを作成

  1. Google Form を開く
  2. メニュー → スクリプト エディタ をクリック
  3. Apps Script エディタが開きます

ステップ 2:検証コードを追加

デフォルトのコードを以下に置き換えます:

// 設定
const CONFIG = {
  API_KEY: 'YOUR_EMAILVERIFY_API_KEY',
  EMAIL_FIELD_INDEX: 1, // フォームに応じて調整(0 始まり)
  BLOCK_DISPOSABLE: true,
  NOTIFY_ON_INVALID: true,
  NOTIFICATION_EMAIL: 'admin@yourcompany.com',
};

/**
 * トリガー関数 - フォーム送信時に実行
 */
function onFormSubmit(e) {
  const response = e.response;
  const email = getEmailFromResponse(response);

  if (!email) {
    Logger.log('回答にメールが見つかりません');
    return;
  }

  // メールを検証
  const result = verifyEmail(email);

  // 結果を保存
  storeVerificationResult(response, result);

  // 無効なメールを処理
  if (!result.isValid) {
    handleInvalidEmail(response, email, result);
  }
}

/**
 * フォーム回答からメールを抽出
 */
function getEmailFromResponse(response) {
  const itemResponses = response.getItemResponses();

  // メールフィールドをタイプで検索
  for (const itemResponse of itemResponses) {
    const item = itemResponse.getItem();
    const itemType = item.getType();

    // メール検証のテキストアイテムかチェック
    if (itemType === FormApp.ItemType.TEXT) {
      const textItem = item.asTextItem();
      const validation = textItem.getValidation();

      // メール形式が必須の場合
      if (validation) {
        return itemResponse.getResponse();
      }
    }
  }

  // フォールバック:設定されたインデックスを使用
  if (CONFIG.EMAIL_FIELD_INDEX < itemResponses.length) {
    return itemResponses[CONFIG.EMAIL_FIELD_INDEX].getResponse();
  }

  return null;
}

/**
 * EmailVerify API を呼び出してメールを検証
 */
function verifyEmail(email) {
  const url = 'https://api.emailverify.ai/v1/verify';

  const options = {
    method: 'post',
    contentType: 'application/json',
    headers: {
      'Authorization': 'Bearer ' + CONFIG.API_KEY,
    },
    payload: JSON.stringify({ email: email }),
    muteHttpExceptions: true,
  };

  try {
    const response = UrlFetchApp.fetch(url, options);
    const data = JSON.parse(response.getContentText());

    const isValid = data.status === 'valid' &&
      !(CONFIG.BLOCK_DISPOSABLE && data.result?.disposable);

    return {
      email: email,
      status: data.status,
      score: data.score,
      isDisposable: data.result?.disposable || false,
      isRole: data.result?.role || false,
      isValid: isValid,
      raw: data,
    };
  } catch (error) {
    Logger.log('検証エラー: ' + error.message);
    return {
      email: email,
      status: 'error',
      isValid: true, // エラー時は許可
      error: error.message,
    };
  }
}

/**
 * 検証結果をリンクされたスプレッドシートに保存
 */
function storeVerificationResult(response, result) {
  const form = FormApp.getActiveForm();
  const destinationId = form.getDestinationId();

  if (!destinationId) {
    Logger.log('リンクされたスプレッドシートがありません');
    return;
  }

  const spreadsheet = SpreadsheetApp.openById(destinationId);
  const sheet = spreadsheet.getSheets()[0];

  // 回答の行を見つける
  const responseRow = findResponseRow(sheet, response);

  if (responseRow === -1) {
    Logger.log('回答の行が見つかりません');
    return;
  }

  // 検証列を追加(存在しない場合)
  ensureVerificationColumns(sheet);

  // 列インデックスを取得
  const headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
  const statusCol = headers.indexOf('メールステータス') + 1;
  const scoreCol = headers.indexOf('メールスコア') + 1;
  const disposableCol = headers.indexOf('使い捨て') + 1;

  // 行を更新
  if (statusCol > 0) {
    sheet.getRange(responseRow, statusCol).setValue(result.status);
  }
  if (scoreCol > 0 && result.score !== undefined) {
    sheet.getRange(responseRow, scoreCol).setValue(result.score);
  }
  if (disposableCol > 0) {
    sheet.getRange(responseRow, disposableCol).setValue(result.isDisposable ? 'はい' : 'いいえ');
  }

  // 条件付き書式を適用
  if (result.status === 'invalid' || result.isDisposable) {
    sheet.getRange(responseRow, 1, 1, sheet.getLastColumn())
      .setBackground('#ffcccb');
  }
}

/**
 * 回答の行番号を見つける
 */
function findResponseRow(sheet, response) {
  const timestamp = response.getTimestamp();
  const data = sheet.getDataRange().getValues();

  for (let i = 1; i < data.length; i++) {
    const rowTimestamp = data[i][0];
    if (rowTimestamp instanceof Date &&
        Math.abs(rowTimestamp.getTime() - timestamp.getTime()) < 5000) {
      return i + 1; // 1 始まり
    }
  }

  return -1;
}

/**
 * スプレッドシートに検証列を追加
 */
function ensureVerificationColumns(sheet) {
  const headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
  const columnsToAdd = ['メールステータス', 'メールスコア', '使い捨て'];

  for (const column of columnsToAdd) {
    if (!headers.includes(column)) {
      const newCol = sheet.getLastColumn() + 1;
      sheet.getRange(1, newCol).setValue(column);
    }
  }
}

/**
 * 無効なメール送信を処理
 */
function handleInvalidEmail(response, email, result) {
  if (!CONFIG.NOTIFY_ON_INVALID) {
    return;
  }

  const form = FormApp.getActiveForm();
  const formTitle = form.getTitle();

  const subject = `[${formTitle}] 無効なメール送信`;
  const body = `
フォームに無効なメールが送信されました。

フォーム: ${formTitle}
メール: ${email}
ステータス: ${result.status}
${result.isDisposable ? '注意: 使い捨てメールを検出' : ''}
スコア: ${result.score || 'N/A'}

タイムスタンプ: ${response.getTimestamp()}
  `.trim();

  MailApp.sendEmail({
    to: CONFIG.NOTIFICATION_EMAIL,
    subject: subject,
    body: body,
  });
}

/**
 * フォーム送信トリガーをセットアップ
 * トリガーをインストールするにはこの関数を一度実行
 */
function installTrigger() {
  const form = FormApp.getActiveForm();

  // 既存のトリガーを削除
  const triggers = ScriptApp.getUserTriggers(form);
  for (const trigger of triggers) {
    if (trigger.getHandlerFunction() === 'onFormSubmit') {
      ScriptApp.deleteTrigger(trigger);
    }
  }

  // 新しいトリガーをインストール
  ScriptApp.newTrigger('onFormSubmit')
    .forForm(form)
    .onFormSubmit()
    .create();

  Logger.log('トリガーが正常にインストールされました');
}

/**
 * 検証テスト(手動実行)
 */
function testVerification() {
  const result = verifyEmail('test@example.com');
  Logger.log(JSON.stringify(result, null, 2));
}

ステップ 3:トリガーをインストール

  1. Apps Script エディタで、関数ドロップダウンから installTrigger を選択
  2. 実行 をクリック
  3. プロンプトが表示されたら必要な権限を付与

ステップ 4:連携をテスト

  1. フォームにテスト回答を送信
  2. リンクされたスプレッドシートで検証結果を確認
  3. Apps Script ログを確認:左サイドバーの 実行

方法 2:スプレッドシートアドオン

カスタムサイドバーで Google Sheets からメールを直接検証します。

アドオンコードの作成

// Code.gs
function onOpen() {
  const ui = SpreadsheetApp.getUi();
  ui.createMenu('EmailVerify')
    .addItem('選択したメールを検証', 'verifySelected')
    .addItem('すべてのメールを検証', 'verifyAll')
    .addItem('設定', 'showSettings')
    .addToUi();
}

function verifySelected() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const range = sheet.getActiveRange();
  const values = range.getValues();

  const results = [];

  for (let i = 0; i < values.length; i++) {
    const email = values[i][0];

    if (!email || !isValidEmailFormat(email)) {
      results.push(['無効な形式']);
      continue;
    }

    const result = verifyEmail(email);
    results.push([result.status + (result.isDisposable ? ' (使い捨て)' : '')]);
  }

  // 結果を次の列に書き込む
  const startCol = range.getColumn() + range.getNumColumns();
  sheet.getRange(range.getRow(), startCol, results.length, 1).setValues(results);
}

function verifyAll() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const ui = SpreadsheetApp.getUi();

  // メール列を尋ねる
  const response = ui.prompt(
    'すべてのメールを検証',
    'メールが含まれる列の文字を入力してください(例:B):',
    ui.ButtonSet.OK_CANCEL
  );

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

  const column = response.getResponseText().toUpperCase();
  const colIndex = column.charCodeAt(0) - 64; // A=1, B=2, など

  const lastRow = sheet.getLastRow();
  const emailRange = sheet.getRange(2, colIndex, lastRow - 1, 1);
  const emails = emailRange.getValues().flat().filter(e => e);

  ui.alert(`${emails.length} 件のメールの検証を開始します...`);

  // バッチで検証
  const batchSize = 50;
  let processed = 0;

  for (let i = 0; i < emails.length; i += batchSize) {
    const batch = emails.slice(i, i + batchSize);

    for (let j = 0; j < batch.length; j++) {
      const email = batch[j];
      const rowIndex = i + j + 2; // +2 for header and 0-index

      if (!isValidEmailFormat(email)) {
        sheet.getRange(rowIndex, colIndex + 1).setValue('無効な形式');
        continue;
      }

      const result = verifyEmail(email);

      // ステータスを書き込む
      sheet.getRange(rowIndex, colIndex + 1).setValue(result.status);

      // スコアを書き込む
      if (result.score !== undefined) {
        sheet.getRange(rowIndex, colIndex + 2).setValue(result.score);
      }

      // 無効なものをハイライト
      if (result.status === 'invalid' || result.isDisposable) {
        sheet.getRange(rowIndex, 1, 1, sheet.getLastColumn()).setBackground('#ffcccb');
      }
    }

    processed += batch.length;
    SpreadsheetApp.flush();

    // レート制限を避ける
    if (i + batchSize < emails.length) {
      Utilities.sleep(1000);
    }
  }

  ui.alert(`検証完了!${processed} 件のメールを処理しました。`);
}

function isValidEmailFormat(email) {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

function showSettings() {
  const html = HtmlService.createHtmlOutputFromFile('Settings')
    .setWidth(400)
    .setHeight(300);
  SpreadsheetApp.getUi().showModalDialog(html, 'EmailVerify 設定');
}

function saveSettings(apiKey) {
  PropertiesService.getUserProperties().setProperty('EMAILVERIFY_API_KEY', apiKey);
  return { success: true };
}

function getApiKey() {
  return PropertiesService.getUserProperties().getProperty('EMAILVERIFY_API_KEY') || '';
}

設定 HTML

<!-- Settings.html -->
<!DOCTYPE html>
<html>
<head>
  <style>
    body {
      font-family: Arial, sans-serif;
      padding: 20px;
    }
    .form-group {
      margin-bottom: 15px;
    }
    label {
      display: block;
      margin-bottom: 5px;
      font-weight: bold;
    }
    input[type="text"] {
      width: 100%;
      padding: 8px;
      border: 1px solid #ddd;
      border-radius: 4px;
      box-sizing: border-box;
    }
    button {
      background-color: #4285f4;
      color: white;
      padding: 10px 20px;
      border: none;
      border-radius: 4px;
      cursor: pointer;
    }
    button:hover {
      background-color: #357abd;
    }
    .success {
      color: #28a745;
      margin-top: 10px;
    }
  </style>
</head>
<body>
  <div class="form-group">
    <label for="apiKey">EmailVerify API キー</label>
    <input type="text" id="apiKey" placeholder="bv_live_xxx" />
  </div>

  <button onclick="saveSettings()">設定を保存</button>

  <div id="message" class="success" style="display: none;"></div>

  <script>
    // 既存の設定を読み込む
    google.script.run.withSuccessHandler(function(apiKey) {
      document.getElementById('apiKey').value = apiKey;
    }).getApiKey();

    function saveSettings() {
      const apiKey = document.getElementById('apiKey').value;

      google.script.run.withSuccessHandler(function(result) {
        if (result.success) {
          document.getElementById('message').textContent = '設定を保存しました!';
          document.getElementById('message').style.display = 'block';
          setTimeout(function() {
            google.script.host.close();
          }, 1500);
        }
      }).saveSettings(apiKey);
    }
  </script>
</body>
</html>

方法 3:Zapier 連携

Zapier を使用して Google Forms を EmailVerify に接続します。

Zap のセットアップ

  1. トリガー:Google Forms → New Response in Spreadsheet
  2. アクション 1:Webhooks by Zapier → POST to EmailVerify
  3. アクション 2:Google Sheets → Update Spreadsheet Row

Webhook の設定

URL: https://api.emailverify.ai/v1/verify
Method: POST
Headers:
  Authorization: Bearer YOUR_API_KEY
  Content-Type: application/json
Data:
{
  "email": "{{email_field_value}}"
}

行の更新

検証結果をスプレッドシートにマッピング:

  • 列:メールステータス → {{status}}
  • 列:メールスコア → {{score}}
  • 列:使い捨て → {{result__disposable}}

ベストプラクティス

1. API キーを安全に保管

// ハードコードの代わりに Properties Service を使用
const apiKey = PropertiesService.getScriptProperties().getProperty('API_KEY');

2. レート制限を処理

function verifyWithRetry(email, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    const result = verifyEmail(email);

    if (result.status !== 'error' || !result.error.includes('rate')) {
      return result;
    }

    // 待機して再試行
    Utilities.sleep(2000 * (i + 1));
  }

  return { status: 'error', error: 'Max retries exceeded' };
}

3. 適切なエラーハンドリング

// API エラー時はフォーム送信をブロックしない
if (result.error) {
  Logger.log('検証に失敗、送信を許可');
  return; // 送信をブロックしない
}

関連リソース

On this page