How to Update Google Sheets When an Email Arrives: 4 Ways

VRVictor RSeptember 16, 20269 min read

Somewhere in your business there is a spreadsheet that is supposed to be the record: the order log, the claims tracker, the job list, the pipeline. And somewhere in your inbox is the email that should have updated it an hour ago.

The gap between those two things is filled by a person copying details across by hand, usually at the end of the day, usually from memory of which emails mattered. That works until volume rises, and then the sheet stops being the record and starts being a rough guess that everyone quietly stops trusting.

This article covers four ways to close that gap, from copy-paste to an assistant that reads the email for you, and the one design decision that determines whether any of them actually work.

Disclosure: we make InboxPilot, an AI email assistant that drafts replies inside Gmail and Outlook and can log what it handles to Google Sheets. The Apps Script and no-code approaches below work with no InboxPilot involved, and the script is yours to copy.

Key takeaways

Append or update? Decide this first

Almost everyone describing this task says "update the spreadsheet." Almost everyone actually means "add a row."

The distinction matters because updating an existing row requires something the email must carry: a value that identifies which row it belongs to. An order number, an invoice number, a ticket reference. The automation reads a key column, finds the matching row, and writes into it.

If that key does not exist, or it is not reliably present in every email, there is nothing to match on. The automation cannot know whether this email is about a record you already have, so it appends. That is not a failure — appending is the safer behaviour by a wide margin, because an append can never destroy a row you depend on, and a bad match can.

So decide up front:

  • Append only. Every email becomes a new row. The sheet becomes a log. Nothing already in it is ever touched. This is what you want for audit trails, intake logs, and anything you will summarise with a pivot table later.
  • Update by key. Emails carry an identifier, and the automation edits the matching row. This is what you want for a status tracker where each order has exactly one row. It needs a key column and a plan for what happens when no row matches.

A good rule: start with append. Add updating only once you have watched real emails for a week and confirmed the key is genuinely always there.

Option 1: copy it across by hand

Worth stating plainly, because for a lot of teams it is still the right answer. Under roughly ten emails a day, a person skimming the inbox and filling in rows is accurate, free, and needs no maintenance.

It stops being the right answer at the point where the copying gets deferred. The moment rows are entered "later," the sheet is no longer a record of what happened; it is a record of what someone remembered. That is the signal to automate, not the raw volume.

Option 2: Google Apps Script (free, Gmail only)

Apps Script runs inside your Google account, costs nothing, and involves no third-party service holding your mail. It is the best-value option if you are comfortable with a little JavaScript.

One thing to understand before you start: Apps Script has no "when an email arrives" trigger. Gmail exposes no such event to it. What you get is a time-driven trigger that runs your function on a schedule, as often as every minute. In practice you are polling, and "instantly" means "within a few minutes."

The setup:

  1. In Gmail, create a filter that applies a label — say to-sheet — to the messages you want logged. This keeps the script's work small and makes it obvious what is in scope.
  2. Open your spreadsheet, choose Extensions → Apps Script, and paste the function below.
  3. Replace the spreadsheet ID and tab name. The ID is the long string in the sheet's URL between /d/ and /edit.
  4. In the Apps Script editor, open Triggers, add a trigger for logNewEmailsToSheet, and set it to time-driven, every 5 minutes.
  5. Run it once by hand first, so Google prompts you for authorisation.
function logNewEmailsToSheet() {
  const LABEL_NAME = 'to-sheet';
  const SHEET_ID = 'YOUR_SPREADSHEET_ID';
  const TAB_NAME = 'Log';

  const sheet = SpreadsheetApp.openById(SHEET_ID).getSheetByName(TAB_NAME);
  if (!sheet) throw new Error('No tab named ' + TAB_NAME);

  const label = GmailApp.getUserLabelByName(LABEL_NAME);
  if (!label) throw new Error('No Gmail label named ' + LABEL_NAME);

  // Column A holds the Gmail message id. Reading it back is what stops a
  // re-run, or an overlapping run, from logging the same email twice.
  const lastRow = sheet.getLastRow();
  const seen = new Set(
    lastRow > 1
      ? sheet.getRange(2, 1, lastRow - 1, 1).getValues().flat().filter(String)
      : []
  );

  const rows = [];
  label.getThreads(0, 50).forEach(function (thread) {
    thread.getMessages().forEach(function (message) {
      const id = message.getId();
      if (seen.has(id)) return;
      seen.add(id);
      rows.push([
        id,
        message.getDate(),
        message.getFrom(),
        message.getSubject(),
        message.getPlainBody().slice(0, 500),
      ]);
    });
  });

  if (rows.length) {
    sheet
      .getRange(sheet.getLastRow() + 1, 1, rows.length, rows[0].length)
      .setValues(rows);
  }
}

That appends. If you want to update by key instead, the shape is a lookup against a key column:

function upsertByKey(sheet, key, values) {
  const lastRow = sheet.getLastRow();
  const keys =
    lastRow > 1
      ? sheet.getRange(2, 1, lastRow - 1, 1).getValues().flat()
      : [];

  const index = keys.indexOf(key);
  if (index === -1) {
    sheet.appendRow([key].concat(values));
  } else {
    // +2 because the data starts on row 2 and indexOf is zero-based.
    sheet.getRange(index + 2, 2, 1, values.length).setValues([values]);
  }
}

Extracting that key from the email is the hard part, and it is where this approach starts to strain. A regular expression over the subject line works right up until a customer writes "order 48812" in the body instead, or writes "#48812", or forwards a thread where three order numbers appear.

Limits worth knowing: consumer Gmail accounts get roughly 20,000 Apps Script URL-fetch-free operations and 90 minutes of runtime per day, which is far more than this needs; the real constraint is that a failing trigger emails you and then keeps failing quietly.

Let InboxPilot draft your replies.

Option 3: a no-code automation tool

Zapier, Make, and Power Automate all ship a Gmail or Outlook trigger and a Google Sheets action, and you can wire them together in about ten minutes with no code. Power Automate is the one to reach for on Microsoft 365, since it has a genuine on-new-email trigger and can write to Excel as well as Sheets.

What you are buying is the connection and the retry logic. What you are still responsible for is the parsing: these tools hand you the subject and body as text, and mapping "the order number" to a column means either a formatter step or a regular expression, with the same brittleness as the script.

The other consideration is pricing shape. These platforms bill per task, so cost scales with email volume rather than with value. A busy shared inbox can make a simple two-step automation surprisingly expensive.

Option 4: let an assistant read the email

The three options above share a limitation: they match patterns. They do well when email is machine-generated and uniform — shipping notifications, form submissions, alerts — and they do badly when a human wrote it.

An AI assistant that already reads the inbox is working from the meaning of the message instead. It can pull the order number whether it appeared as "order 48812," "#48812," or "the order I placed on the 3rd," because it is reading the sentence rather than testing it against a regex.

This is how InboxPilot's Google Sheets connection works. You link a spreadsheet, pick the tab, and map the columns once. From then on:

  • It appends a row for every email it handles. Rows are only ever added. Nothing already in your spreadsheet is edited or deleted, so a mistake in the automation cannot overwrite a record you rely on.
  • It reads the same tab back as reference data. This is the half that pattern-matching tools cannot do at all: when a customer asks where their order is, the draft reply quotes the ship date and tracking number out of your sheet, instead of a person going to look them up.
  • It works the same on Outlook. The connection sits on the email pipeline rather than on one mail provider.

The honest limitation: because it appends rather than updates, it is a logging and lookup tool, not a two-way sync. If you need one row per order, edited in place, a keyed Apps Script or Power Automate flow is the better fit today. And Excel is not supported yet — Google Sheets is the only spreadsheet it connects to.

Which option fits your team

  • Under ten emails a day, or highly irregular. Keep copying by hand. Automating a small, varied workload usually costs more attention than it saves.
  • Uniform, machine-generated email. Apps Script. The format is stable, so pattern matching holds, and it is free.
  • You want it working this afternoon and volume is modest. A no-code tool. Watch the per-task pricing as volume grows.
  • Humans wrote the emails, and someone also has to reply to them. An assistant that reads the inbox. The logging is worth less than the fact that the reply gets drafted from the same sheet.
  • You need one row per record, edited in place. Apps Script with a key column, or Power Automate. Be sure the key is genuinely in every message first.

Four things that break these setups

Duplicates. Any polling automation will eventually process the same email twice, whether from an overlapping run, a retry, or a re-labelled thread. Write something immutable into a column — the Gmail message id is ideal — and check it before writing. The script above does this.

Free-text parsing. Regular expressions over human writing fail on the cases you did not think of, and they fail silently, producing a row with a blank column rather than an error. Whatever you build, review the first week's rows by hand before you trust it.

Locale and dates. A spreadsheet set to a different locale than the script will reinterpret 03/09 without telling you. Write dates as real date objects rather than strings, and set the sheet's locale deliberately under File → Settings.

Permissions drifting. Scripts run as the person who authorised them. When that person leaves, or their password changes, the trigger stops and the only signal is a failure email to an inbox nobody reads. Authorise shared automations from an account that outlives individuals.

Where to go next

If the emails you want logged are customers asking about orders, the WISMO and order status workflow covers the reply side of the same problem. If you are weighing up Gmail automation more broadly, seven Gmail setups that work starts with filters and labels and builds up from there.

And if the sheet you are trying to keep current is also the sheet your team quotes from when they reply, that is the case where logging to Google Sheets earns its place: the row goes in, and the next reply comes back out of it.

Frequently asked questions

Can Google Sheets update automatically when I get an email?

Yes, but nothing inside Google Sheets watches your inbox on its own. Something has to do the watching: an Apps Script trigger that polls Gmail on a schedule, a no-code automation tool, or an assistant that already reads the inbox. Sheets itself has no email trigger, which is why every working setup involves a second piece.

How do I send Gmail data to Google Sheets without Zapier?

Google Apps Script does it for free and runs on Google's infrastructure. You write a function that searches a Gmail label, appends the messages it finds to a sheet, and set a time-driven trigger to run it every few minutes. There is a working script in this article. The tradeoff is that you own the code and the edge cases.

Can a script update an existing row instead of adding a new one?

Only if every email carries a value that identifies the row, such as an order or invoice number, and that value lives in a known column. The script reads the key column, looks for a match, and writes to that row if it finds one or appends if it does not. Without a reliable key there is nothing to match on, and 'update' quietly becomes 'append'.

Does this work with Outlook as well as Gmail?

Apps Script does not: GmailApp only reads Gmail. For Outlook or Microsoft 365 the equivalent is Power Automate, which has an on-new-email trigger and can write to Excel or Sheets. Tools that sit on the inbox rather than on one provider, InboxPilot included, treat Gmail and Outlook the same way.

Can I do the same with Microsoft Excel?

Yes, through Power Automate, though Excel's connector requires the workbook to live on OneDrive for Business or SharePoint, not on a local drive. InboxPilot supports Google Sheets today and does not yet connect to Excel.

Is it safe to give a tool access to my spreadsheets?

Check the scope it asks for. A connection that only needs to read and write spreadsheets should not be requesting your whole Google Drive. InboxPilot is SOC 2 Type II certified, encrypts data in transit and at rest, asks for spreadsheet access only, and never uses your documents or email to train shared models.

Let InboxPilot draft your replies.

Connect your inbox and InboxPilot drafts a reply on every email, automatically. Free, no card.

View pricingNo credit card required

Start with the emails you’re tired of.

Connect Gmail or Outlook, point InboxPilot at a few documents, and see your first drafts today.

No credit card. Nothing sends without your approval.