Skip to content

Task guide

Send an email for each row in a Google Sheet

Send one email to each person listed on a Customers tab. The script marks each row Sent as it goes, so a later run sends only to rows that are not marked yet.

1 · Prepare

Put these pieces in place

  • Create a Sheet tab named Customers.
  • Put a name in column A, an email address in column B, an amount in column C, and leave column D for the sent status.
  • Send only to people who expect the message. Run the script by hand, and only one person should run it at a time. Wait for each run to finish, and do not edit the rows while it runs.

Change these values

Change these values

Make the code yours before you run it.
Sheet tab name
Customers

This must match the tab that holds your rows.

Email subject
A quick follow-up

Change it to the subject your recipients should see.

Sent status
Sent

A later run skips rows that show this word. Sent means the script called sendEmail for that row. It does not confirm the message arrived, and it cannot prevent every duplicate.

2 · Review before running

What the script can access and change

Permissions you approve

  • See, edit, create, and delete all your Google Sheets spreadsheets. The code only reads the Customers tab and writes Sent into column D of this spreadsheet.
  • Read, compose, send, and permanently delete all your email from Gmail. Google asks for full Gmail access because the code uses GmailApp, but the code only sends one email for each unsent row.

Effects of one run

  • Calls GmailApp.sendEmail for each row with an email address and no Sent status in the initial read.
  • Writes Sent to column D right after each email is sent, so a later run does not send that row again. The script writes one row at a time, instead of all rows at the end, because each email has already gone out as soon as it is sent. If the run stops between the send and the write, or before Sheets saves the write, the email is sent but column D stays empty.

3 · Copy

Paste this into the Apps Script editor

Create or open a script file, replace the example values marked above, then save the project.

Code.gs
function sendSheetFollowUps() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Customers');
  if (!sheet) throw new Error('Add a Sheet tab named Customers before running this function.');

  const firstDataRow = 2;
  const lastRow = sheet.getLastRow();
  if (lastRow < firstDataRow) return;

  const rows = sheet.getRange(firstDataRow, 1, lastRow - firstDataRow + 1, 4).getValues();
  rows.forEach((row, index) => {
    const [name, emailAddress, amount, status] = row;
    if (!emailAddress || status === 'Sent') return;

    const greeting = name ? 'Hello ' + name + ',' : 'Hello,';
    const message = greeting + '\n\nThis is a quick follow-up about ' + amount + '.\n\nThank you.';
    GmailApp.sendEmail(String(emailAddress), 'A quick follow-up', message);
    sheet.getRange(firstDataRow + index, 4).setValue('Sent');
  });
}

4 · Run

Follow these steps in order

  1. Set up one test row

    On the Customers tab, put the four headers in row 1. In row 2, add your own name, your own email address, and an amount, and leave column D empty. Leave every other recipient out until the test works.

  2. Paste and save the function

    Choose Extensions, then Apps Script. Replace the starter function with this one and save.

  3. Run the test

    Choose sendSheetFollowUps in the function dropdown above the code, then click Run. Approve access when Google asks. Check that your test email arrives and that column D of your row now says Sent.

  4. Add the intended recipients

    Only after the test succeeds, add rows for people who expect the message. Wait for the previous run to finish. If it failed, check Gmail Sent before you run again, because an email can be sent even when its row was not marked.

5 · Confirm

How to tell it worked

After a successful run, each processed row shows Sent and its message appears in Gmail Sent.

If the result is different

Troubleshooting

The run stops with "Add a Sheet tab named Customers before running this function."
Rename the tab to Customers, or change the tab name in the code to the name of your tab.
A row got no email and is not marked Sent.
Check that column B in that row holds an email address and that column D is empty. The script skips rows with no address and rows already marked Sent.
A run failed and some status cells are empty.
Do not run the script again yet. In Gmail Sent, compare the recipient, subject, body, and time with each row that has an empty status. Type Sent in a row only after you find its message. If you cannot tell whether a row got an email, do not run the script again until you decide whether a second email is acceptable. Two runs at the same time can also send the same row twice.

Technical details

Names used in this script

Open these details when you want to adapt the example or look up an exact service or method name.

Show Apps Script symbols and service pages

Keep going