Saves each new Gmail message that matches your search as a row in your spreadsheet, and never saves the same message twice.
Uses
Gmail
Google Sheets
Save matching emails to a spreadsheet
Whenever new mail arrives in Gmail, the workflow looks for the messages your search matches, such as everything from a billing address, and writes one row per message into your spreadsheet. Each row records when the message was sent, who sent it, who it went to, the subject, an excerpt of the body, the Gmail message id and a link that opens the message in Gmail.
Nothing is saved twice. Each message is labelled 'Saved to sheet' the moment it is picked up and the search excludes that label, so a message already saved is never fetched again. The label goes on before the row is written on purpose: if the sheet cannot be written to, the label comes off again, the message is retried next run and the run ends in failure so you can see it. Several matching messages landing at once are all saved, and a backlog is worked through a batch at a time.
Before the first run you need a spreadsheet tab with headings in that column order, and a Gmail search that picks out the mail worth saving.
emailSearch to blank.Set emailSearch to blank.spreadsheetUrl to blank.Set spreadsheetUrl to blank.sheetTabName to Emails.Set sheetTabName to Emails.savedLabel to Saved to sheet.Set savedLabel to Saved to sheet.maxEmailsPerRun to 10.Set maxEmailsPerRun to 10.excerptLength to 300.Set excerptLength to 300.gmailAccountIndex to 0.Set gmailAccountIndex to 0.emailLimit to maxEmailsPerRun multiplied by 1.Set emailLimit to maxEmailsPerRun multiplied by 1.emailLimit is greater than or equal to 1 and emailLimit is less than or…If not emailLimit is greater than or equal to 1 and emailLimit is less than or…excerptLimit to excerptLength multiplied by 1.Set excerptLimit to excerptLength multiplied by 1.excerptLimit is greater than or equal to 0 and excerptLimit is less than…If not excerptLimit is greater than or equal to 0 and excerptLimit is less than…accountIndex to gmailAccountIndex multiplied by 1.Set accountIndex to gmailAccountIndex multiplied by 1.accountIndex is greater than or equal to 0 and accountIndex is less than…If not accountIndex is greater than or equal to 0 and accountIndex is less than…'gmailAccountIndex' is not a whole number from 0 up, so the links in the sheet will open in the first Google account you are signed in to..Show in the output: 'gmailAccountIndex' is not a whole number from 0 up, so the links in the sheet will open in the first Google account you are signed in to..accountIndex to 0.Change accountIndex to 0.searchQuery to emailSearch -label:@savedLabel.Set searchQuery to emailSearch -label:@savedLabel.searchQuery. Save it as found.List emails matching searchQuery. Save it as found.matchCount to 0.Set matchCount to 0.listErrorIf a step below fails, save the error as listErrorfound.emails and save it as matchCount.Count the items in found.emails and save it as matchCount.listError as text.Stop and report a problem: Gmail did not return a readable list of messages for the search '@emailSearch', so nothing was saved this run. Details: listError as text.processedCount to 0.Set processedCount to 0.savedCount to 0.Set savedCount to 0.failedCount to 0.Set failedCount to 0.message in found.emails:For each message in found.emails:processedCount is greater than or equal to emailLimitIf processedCount is greater than or equal to emailLimitmessageErrorIf a step below fails, save the error as messageErrormessage.id and save it as messageId.Trim message.id and save it as messageId.messageId is emptyIf messageId is emptyfailedCount.Add 1 to failedCount.Skipped a message that Gmail returned without an id..Show in the output: Skipped a message that Gmail returned without an id..savedLabel to email messageId.Add label savedLabel to email messageId.processedCount.Add 1 to processedCount.subject to (no subject).Set subject to (no subject).missingFieldIf a step below fails, save the error as missingFieldmessage.subject and save it as fieldValue.Trim message.subject and save it as fieldValue.fieldValue isn't emptyIf fieldValue isn't emptysubject to fieldValue.Change subject to fieldValue.sender to (unknown sender).Set sender to (unknown sender).missingFieldIf a step below fails, save the error as missingFieldmessage.from and save it as fieldValue.Trim message.from and save it as fieldValue.fieldValue isn't emptyIf fieldValue isn't emptysender to fieldValue.Change sender to fieldValue.recipient to blank.Set recipient to blank.sentAt.Get the current date and time and save it as sentAt.headers to an empty record.Set headers to an empty record.missingHeadersIf a step below fails, save the error as missingHeadersmessageId. Save it as headers.Get the sender, subject and date of email messageId. Save it as headers.Could not read this message's headers; the row records the time it was saved instead of the time it was sent, and leaves the To column empty..Show in the output: Could not read this message's headers; the row records the time it was saved instead of the time it was sent, and leaves the To column empty..missingDateIf a step below fails, save the error as missingDateheaders.Date and save it as dateHeader.Trim headers.Date and save it as dateHeader.dateHeader isn't emptyIf dateHeader isn't emptysentAt to dateHeader.Change sentAt to dateHeader.missingRecipientIf a step below fails, save the error as missingRecipientheaders.To and save it as toHeader.Trim headers.To and save it as toHeader.toHeader isn't emptyIf toHeader isn't emptyrecipient to toHeader.Change recipient to toHeader.excerpt to blank.Set excerpt to blank.missingTextIf a step below fails, save the error as missingTextmessage.body and save it as sourceText.Trim message.body and save it as sourceText.sourceText to excerptLimit characters and save it as excerpt.Shorten sourceText to excerptLimit characters and save it as excerpt.excerpt is emptyIf excerpt is emptymissingTextIf a step below fails, save the error as missingTextmessage.snippet and save it as sourceText.Trim message.snippet and save it as sourceText.sourceText to excerptLimit characters and save it as excerpt.Shorten sourceText to excerptLimit characters and save it as excerpt.messageLink to https://mail.google.com/mail/u/@accountIndex/#all/@messageId.Set messageLink to https://mail.google.com/mail/u/@accountIndex/#all/@messageId.rowErrorIf a step below fails, save the error as rowErrorsheetTabName in spreadsheetUrl.Add a row to sheetTabName in spreadsheetUrl.savedCount.Add 1 to savedCount.failedCount.Add 1 to failedCount.unlabelErrorIf a step below fails, save the error as unlabelErrorsavedLabel from email messageId.Remove label savedLabel from email messageId.messageId after its row failed - remove it by hand so the message is saved on the next run.Show in the output: Could not take the '@savedLabel' label back off message messageId after its row failed - remove it by hand so the message is saved on the next run.rowError as text.Show in the output: Could not save one email to the sheet; it will be tried again on the next run: rowError as text.failedCount.Add 1 to failedCount.messageError as text.Show in the output: Could not process one email: messageError as text.failedCount is greater than 0If failedCount is greater than 0savedCount email(s) to the sheet, but failedCount could not be saved - the messages above say why. A message that is not saved is tried again on the next run.Stop and report a problem: Saved savedCount email(s) to the sheet, but failedCount could not be saved - the messages above say why. A message that is not saved is tried again on the next run.savedCount is 0If savedCount is 0No new email matching the search to save..Show in the output: No new email matching the search to save..savedCount email(s) to the sheet.Show in the output: Saved savedCount email(s) to the sheet.