The problem

You have data in a Google Sheet and you need it to trigger an email. Maybe it's a status change that should notify someone. Maybe it's a new row from a form that needs a follow-up. Maybe it's a cell hitting a threshold that should alert your team. Right now you're doing it manually. You check the sheet, see the change, open Gmail, type the email, paste the relevant info, send it. Or worse, you forget to check and the email never goes out. Google Sheets can send emails on its own using Apps Script. The script watches for changes and sends the right email to the right person when the right thing happens. No manual checking, no forgotten follow-ups. This guide covers the four most common triggers: sending an email when a cell value changes, when a new row is added, when a checkbox is checked, and on a schedule.

Trigger 1: Send email when a cell value changes

This is the most common use case. A status column changes from "Pending" to "Approved," and an email goes out automatically. Open your Google Sheet. Click Extensions, then Apps Script. Delete any existing code and paste this:

javascript
function onEdit(e) {
  var sheet =
  e.source.getActiveSheet();
  var range = e.range;

  // === CONFIGURATION ===
  var watchColumn = 7;        // column G (status column)
  var triggerValue = 'Approved';
  var emailColumn = 3;        // column C (email address)
  var nameColumn = 2;         // column B (person's name)
  var sheetName = 'Sheet1';   // tab name to watch
  // === END CONFIGURATION ===

  if (sheet.getName() !== sheetName)
  return;
  if (range.getColumn() !==
  watchColumn) return;
  if (range.getValue() !==
  triggerValue) return;

  var row = range.getRow();
  var email = sheet.getRange(row, emailColumn).getValue();
  var name = sheet.getRange(row,
  nameColumn).getValue();

  if (!email ||
  !email.toString().includes('@')) return;

  MailApp.sendEmail({
    to: email,
    subject: 'Your request has been
  approved',
    body: 'Hi ' + name + ',\n\nYour
  request has been approved. No further action is needed on your end.\n\nThank
  you.'
  });

  // Mark that the email was sent
  sheet.getRange(row, watchColumn +
  1).setValue('Email sent ' + new Date().toLocaleDateString());
}

This script fires every time any cell in the sheet is edited. It checks whether the edit happened in the column and tab you specified, and whether the new value matches your trigger. If all conditions match, it sends the email and marks the row. Important: The onEdit trigger runs automatically. You don't need to set up a trigger manually. Just save the script, authorize it by running it once from the editor, and it's active. Change the column numbers, trigger value, email subject, and body to match your use case.

Trigger 2: Send email when a new row is added

Useful when new data arrives from a Google Form, an integration, or manual entry, and you want an immediate notification.

javascript
function onNewRow(e) {
  var sheet =
  SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
  var row = sheet.getLastRow();
  var headers = sheet.getRange(1, 1,
  1, sheet.getLastColumn()).getValues()[0];
  var data = sheet.getRange(row, 1,
  1, sheet.getLastColumn()).getValues()[0];

  // === CONFIGURATION ===
  var notifyEmail =
  'you@company.com';
  // === END CONFIGURATION ===

  var body = 'A new row was added to
  your sheet:\n\n';
  for (var i = 0; i <
  headers.length; i++) {
    if (headers[i] &&
  data[i]) {
      body += headers[i] + ': ' +
  data[i] + '\n';
    }
  }

  MailApp.sendEmail({
    to: notifyEmail,
    subject: 'New entry added to ' +
  sheet.getName(),
    body: body
  });
}

For this one, you do need to set up a trigger manually. Go to the clock icon in Apps Script, click "Add Trigger," select onNewRow, event source "From spreadsheet," event type "On form submit" (if the rows come from a form) or "On change" (if rows are added manually or by integration).

Trigger 3: Send email when a checkbox is checked

Great for simple approval workflows. Someone checks a box, the email fires.

javascript
function onEdit(e) {
  var sheet =
  e.source.getActiveSheet();
  var range = e.range;

  // === CONFIGURATION ===
  var checkboxColumn = 8;     // column H (checkbox)
  var emailColumn = 3;        // column C
  var nameColumn = 2;         // column B
  var sheetName = 'Tasks';
  // === END CONFIGURATION ===

  if (sheet.getName() !== sheetName)
  return;
  if (range.getColumn() !==
  checkboxColumn) return;
  if (range.getValue() !== true)
  return;

  var row = range.getRow();
  var email = sheet.getRange(row,
  emailColumn).getValue();
  var name = sheet.getRange(row,
  nameColumn).getValue();

  if (!email ||
  !email.toString().includes('@')) return;

  MailApp.sendEmail({
    to: email,
    subject: 'Task completed',
    body: 'Hi ' + name + ',\n\nThe
  task on row ' + row + ' has been marked as complete.\n\nThank you.'
  });
}

This uses the same onEdit trigger as the cell change example. If you need both (cell value changes AND checkbox triggers), combine them into one onEdit function with multiple condition checks.

Trigger 4: Send email on a schedule

Send a summary, report, or reminder at a set time every day or week. This doesn't depend on sheet changes. It just runs on a clock.

javascript
function sendScheduledEmail() {
  var sheet =
  SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Summary');

  // === CONFIGURATION ===
  var recipient =
  'team@company.com';
  var subject = 'Daily Summary';
  // === END CONFIGURATION ===

  var totalTasks =
  sheet.getRange('B2').getValue();
  var completed =
  sheet.getRange('B3').getValue();
  var pending =
  sheet.getRange('B4').getValue();

  var body = 'Daily summary as of ' +
  new Date().toLocaleDateString() + ':\n\n'
    + 'Total tasks: ' + totalTasks +
  '\n'
    + 'Completed: ' + completed +
  '\n'
    + 'Pending: ' + pending +
  '\n';

  MailApp.sendEmail(recipient,
  subject, body);
}

Set up a time-driven trigger: clock icon, "Add Trigger," select sendScheduledEmail, event source "Time-driven," then choose your frequency (daily, weekly, etc.) and time window.

How to extend this

Send HTML-formatted emails. Replace body with htmlBody in the sendEmail call. Build your email content using HTML tags for formatting, tables, colors, and layout. CC or BCC additional recipients. Add cc or bcc to the sendEmail options: MailApp.sendEmail({to: email, cc: 'manager@company.com', subject: '...', body: '...'}); Attach a file from Drive. Add an attachments parameter: attachments: [DriveApp.getFileById('fileId').getAs(MimeType.PDF)] Prevent duplicate sends. Add a "Sent" column. Before sending, check if that column already has a value. After sending, write a timestamp. This prevents re-sends if the trigger fires twice.

Common issues

onEdit doesn't fire. The simple onEdit trigger cannot send emails because it runs with limited permissions. You need to install it as a trigger manually: go to Triggers, add onEdit, event source "From spreadsheet," event type "On edit." This gives it the permissions it needs to use MailApp. Email sends but looks blank. Check that your cell references are pulling the right data. Add a Logger.log(body) line before the sendEmail call, then check View > Logs to see what the script is building. "You do not have permission to call MailApp.sendEmail." Run the function once manually from the Apps Script editor and approve the permissions when prompted. Emails go to spam. Emails sent from Apps Script come from your Gmail address. They can still hit spam filters if the subject or body looks generic. Use a specific, professional subject line and include the recipient's name in the body.