Reads order emails hourly, has AI pull out each line item, and appends it to your order sheet.

UsesGmailGoogle SheetsOpenAI

Turn order emails into spreadsheet rows

Every hour, the order emails matching your Gmail search are read from your inbox, an AI pulls out who is ordering and every item and quantity, and one row per item is added to the tab you name in your spreadsheet. Each row records the customer, order reference, item, quantity, requested delivery date and the email it came from, so any row can be traced back. An order that gives no reference or delivery date is still logged, with 'Not given' in that column.

The workflow refuses to guess. If an email is not clearly an order, or any item's name or quantity is missing or unclear, nothing from it is written and it is labelled 'Order needs review' for a person. Handled emails are labelled 'Order logged' and both labels are left out of the search, so no order is recorded twice. If the AI cannot be reached or the sheet will not take rows, the emails are left unlabelled to be tried again next hour and the run is marked as failed, saying what went wrong.

You need Gmail, Google Sheets and OpenAI connected, a link to your spreadsheet, the tab's name with the six headings in row 1, and a Gmail search that finds your order emails.

ScheduleRun every hour.Run every hour.
ValuesSet spreadsheetUrl to blank.Set spreadsheetUrl to blank.
ValuesSet sheetName to blank.Set sheetName to blank.
ValuesSet orderEmailSearch to blank.Set orderEmailSearch to blank.
ValuesSet maxEmails to 25.Set maxEmails to 25.
ValuesSet loggedLabel to Order logged.Set loggedLabel to Order logged.
ValuesSet reviewLabel to Order needs review.Set reviewLabel to Order needs review.
ValuesSet tabHeadings to an empty list.Set tabHeadings to an empty list.
Decisions & LoopsIf a step below fails, save the error as tabErrorIf a step below fails, save the error as tabError
Try
Google SheetsGoogle SheetsRead the rows of spreadsheetUrl. Save it as orderTab.Read the rows of spreadsheetUrl. Save it as orderTab.
ValuesChange tabHeadings to orderTab.headers.Change tabHeadings to orderTab.headers.
On error
Decisions & LoopsStop and report a problem: Could not open the '@sheetName' tab of your order spreadsheet (tabError.message). Check the link in 'spreadsheetUrl' and the tab name in 'sheetName', then run it again.Stop and report a problem: Could not open the '@sheetName' tab of your order spreadsheet (tabError.message). Check the link in 'spreadsheetUrl' and the tab name in 'sheetName', then run it again.
Decisions & LoopsIf tabHeadings is emptyIf tabHeadings is empty
Yes
Decisions & LoopsStop and report a problem: The '@sheetName' tab is empty. Type these headings into row 1, one per column and in this order, then run it again: Customer, Order reference, Item, Quantity, Requested delivery date, Gmail message ID.Stop and report a problem: The '@sheetName' tab is empty. Type these headings into row 1, one per column and in this order, then run it again: Customer, Order reference, Item, Quantity, Requested delivery date, Gmail message ID.
No
No steps
ListsTake the first 6 items of tabHeadings and save it as firstHeadings.Take the first 6 items of tabHeadings and save it as firstHeadings.
TextJoin firstHeadings with , and save it as headingLine.Join firstHeadings with , and save it as headingLine.
Decisions & LoopsIf headingLine in lowercase is not "customer, order reference, item, quantity,…If headingLine in lowercase is not "customer, order reference, item, quantity,…
Yes
Decisions & LoopsStop and report a problem: Rows are added to the '@sheetName' tab column by column, so row 1 must read: Customer, Order reference, Item, Quantity, Requested delivery date, Gmail message ID. It reads: headingLine. Fix the headings, then run it again.Stop and report a problem: Rows are added to the '@sheetName' tab column by column, so row 1 must read: Customer, Order reference, Item, Quantity, Requested delivery date, Gmail message ID. It reads: headingLine. Fix the headings, then run it again.
No
No steps
GmailGmailList emails matching '@orderEmailSearch -label:@loggedLabel -label:@reviewLabel'. Save it as inbox.List emails matching '@orderEmailSearch -label:@loggedLabel -label:@reviewLabel'. Save it as inbox.
ValuesSet rowsAdded to 0.Set rowsAdded to 0.
ValuesSet ordersLogged to 0.Set ordersLogged to 0.
ValuesSet reviewNotes to an empty list.Set reviewNotes to an empty list.
ValuesSet failures to an empty list.Set failures to an empty list.
ValuesSet aiFailed to an empty list.Set aiFailed to an empty list.
ValuesSet lastAiProblem to blank.Set lastAiProblem to blank.
Decisions & LoopsFor each email in inbox.emails:For each email in inbox.emails:
TextUse email.subject, or (no subject) if it is empty and save it as subject.Use email.subject, or (no subject) if it is empty and save it as subject.
TextTrim email.body and save it as emailBody.Trim email.body and save it as emailBody.
ValuesSet reviewReason to it has no text to read; an order sent only as an attachment has to be typed in by hand.Set reviewReason to it has no text to read; an order sent only as an attachment has to be typed in by hand.
ValuesSet orderRows to an empty list.Set orderRows to an empty list.
Decisions & LoopsIf emailBody isn't emptyIf emailBody isn't empty
Yes
ValuesSet extracted to an empty record.Set extracted to an empty record.
ValuesSet aiProblem to blank.Set aiProblem to blank.
Decisions & LoopsIf a step below fails, save the error as aiErrorIf a step below fails, save the error as aiError
Try
AI AgentRun an AI agent: Copy the order out of this email. From: email.from Subject: subject emailBody and save it as reading.Run an AI agent: Copy the order out of this email. From: email.from Subject: subject emailBody and save it as reading.
ValuesChange extracted to reading.output.Change extracted to reading.output.
On error
ValuesChange aiProblem to aiError.message.Change aiProblem to aiError.message.
Decisions & LoopsIf aiProblem isn't emptyIf aiProblem isn't empty
Yes
ListsAdd '@subject' to the end of aiFailed and save it as aiFailed.Add '@subject' to the end of aiFailed and save it as aiFailed.
ValuesChange lastAiProblem to aiProblem.Change lastAiProblem to aiProblem.
Decisions & LoopsSkip to the next item.Skip to the next item.
No
No steps
TextTrim extracted.customer and save it as customer.Trim extracted.customer and save it as customer.
TextUse extracted.order_reference, or Not given if it is empty and save it as orderReference.Use extracted.order_reference, or Not given if it is empty and save it as orderReference.
TextUse extracted.delivery_date, or Not given if it is empty and save it as deliveryDate.Use extracted.delivery_date, or Not given if it is empty and save it as deliveryDate.
ValuesSet incompleteLines to 0.Set incompleteLines to 0.
Decisions & LoopsFor each line in extracted.items:For each line in extracted.items:
Text Trim line.item and save it as itemName. Trim line.item and save it as itemName.
Decisions & Loops If itemName isn't empty and line.quantity is greater than 0 If itemName isn't empty and line.quantity is greater than 0
Yes
ListsAdd [customer, orderReference, itemName, line.quantity, deliveryDate, email.id] to the end of orderRows and save it as orderRows.Add [customer, orderReference, itemName, line.quantity, deliveryDate, email.id] to the end of orderRows and save it as orderRows.
No
ValuesAdd 1 to incompleteLines.Add 1 to incompleteLines.
Decisions & LoopsIf extracted.is_order is noIf extracted.is_order is no
Yes
ValuesChange reviewReason to the AI did not see an order in it.Change reviewReason to the AI did not see an order in it.
Else if @extracted.is_order is not "yes"
ValuesChange reviewReason to the AI could not tell whether it places an order.Change reviewReason to the AI could not tell whether it places an order.
Else if @customer is empty
ValuesChange reviewReason to it does not say who the customer is.Change reviewReason to it does not say who the customer is.
Else if @orderRows is empty
ValuesChange reviewReason to no ordered item was found in it.Change reviewReason to no ordered item was found in it.
Else if @incompleteLines is greater than 0
ValuesChange reviewReason to an item's name or quantity is missing or unclear.Change reviewReason to an item's name or quantity is missing or unclear.
Otherwise
ValuesChange reviewReason to blank.Change reviewReason to blank.
No
No steps
Decisions & LoopsIf reviewReason isn't emptyIf reviewReason isn't empty
Yes
Decisions & LoopsIf a step below fails, save the error as reviewLabelErrorIf a step below fails, save the error as reviewLabelError
Try
GmailGmailAdd label reviewLabel to email email. Save it as flagged.Add label reviewLabel to email email. Save it as flagged.
ListsAdd '@subject' (reviewReason) to the end of reviewNotes and save it as reviewNotes.Add '@subject' (reviewReason) to the end of reviewNotes and save it as reviewNotes.
On error
ListsAdd '@subject' needs review (reviewReason) but the label could not be added (reviewLabelError.message) to the end of failures and save it as failures.Add '@subject' needs review (reviewReason) but the label could not be added (reviewLabelError.message) to the end of failures and save it as failures.
Decisions & LoopsSkip to the next item.Skip to the next item.
No
No steps
ValuesSet rowsWritten to 0.Set rowsWritten to 0.
ValuesSet writeProblem to blank.Set writeProblem to blank.
Decisions & LoopsFor each orderRow in orderRows:For each orderRow in orderRows:
Decisions & LoopsIf a step below fails, save the error as sheetErrorIf a step below fails, save the error as sheetError
Try
Google SheetsGoogle SheetsAdd a row to sheetName in spreadsheetUrl. Save it as added.Add a row to sheetName in spreadsheetUrl. Save it as added.
ValuesAdd 1 to rowsWritten.Add 1 to rowsWritten.
On error
ValuesChange writeProblem to sheetError.message.Change writeProblem to sheetError.message.
Decisions & LoopsStop repeating.Stop repeating.
MathChange rowsAdded to rowsAdded plus rowsWritten.Change rowsAdded to rowsAdded plus rowsWritten.
Decisions & LoopsIf writeProblem isn't emptyIf writeProblem isn't empty
Yes
Decisions & LoopsIf rowsWritten is 0If rowsWritten is 0
Yes
ListsAdd no rows could be added to the '@sheetName' tab (writeProblem), so '@subject' and any emails after it were left unlabelled to be tried again next hour to the end of failures and save it as failures.Add no rows could be added to the '@sheetName' tab (writeProblem), so '@subject' and any emails after it were left unlabelled to be tried again next hour to the end of failures and save it as failures.
No
Decisions & LoopsIf a step below fails, save the error as partLabelErrorIf a step below fails, save the error as partLabelError
Try
GmailGmailAdd label reviewLabel to email email. Save it as partlyFlagged.Add label reviewLabel to email email. Save it as partlyFlagged.
On error
No steps
ListsAdd only the first rowsWritten line(s) of '@subject' were added before the sheet stopped taking rows (writeProblem); the email is labelled '@reviewLabel' so the rest can be added by hand, and any emails after it are tried again next hour to the end of failures and save it as failures.Add only the first rowsWritten line(s) of '@subject' were added before the sheet stopped taking rows (writeProblem); the email is labelled '@reviewLabel' so the rest can be added by hand, and any emails after it are tried again next hour to the end of failures and save it as failures.
Decisions & LoopsStop repeating.Stop repeating.
No
No steps
Decisions & LoopsIf a step below fails, save the error as loggedLabelErrorIf a step below fails, save the error as loggedLabelError
Try
GmailGmailAdd label loggedLabel to email email. Save it as logged.Add label loggedLabel to email email. Save it as logged.
ValuesAdd 1 to ordersLogged.Add 1 to ordersLogged.
On error
ListsAdd the rows for '@subject' were added but the '@loggedLabel' label could not be put on the email (loggedLabelError.message): label it by hand, or its rows will be added again next hour to the end of failures and save it as failures.Add the rows for '@subject' were added but the '@loggedLabel' label could not be put on the email (loggedLabelError.message): label it by hand, or its rows will be added again next hour to the end of failures and save it as failures.
Decisions & LoopsIf aiFailed isn't emptyIf aiFailed isn't empty
Yes
TextJoin aiFailed with , and save it as aiFailedList.Join aiFailed with , and save it as aiFailedList.
ListsAdd the AI could not read aiFailedList (lastAiProblem), so they were left unlabelled to be read again next hour to the end of failures and save it as failures.Add the AI could not read aiFailedList (lastAiProblem), so they were left unlabelled to be read again next hour to the end of failures and save it as failures.
No
No steps
ValuesSet reportLines to an empty list.Set reportLines to an empty list.
ListsAdd Added rowsAdded row(s) from ordersLogged order email(s). to the end of reportLines and save it as reportLines.Add Added rowsAdded row(s) from ordersLogged order email(s). to the end of reportLines and save it as reportLines.
Decisions & LoopsIf reviewNotes isn't emptyIf reviewNotes isn't empty
Yes
TextJoin reviewNotes with ; and save it as reviewList.Join reviewNotes with ; and save it as reviewList.
ListsAdd Labelled '@reviewLabel' for a person to check: reviewList. to the end of reportLines and save it as reportLines.Add Labelled '@reviewLabel' for a person to check: reviewList. to the end of reportLines and save it as reportLines.
No
No steps
Decisions & LoopsIf the length of inbox.emails is greater than or equal to maxEmailsIf the length of inbox.emails is greater than or equal to maxEmails
Yes
ListsAdd Only maxEmails emails are read per run, so more may be waiting; they are read next hour. to the end of reportLines and save it as reportLines.Add Only maxEmails emails are read per run, so more may be waiting; they are read next hour. to the end of reportLines and save it as reportLines.
No
No steps
TextJoin reportLines with a space and save it as report.Join reportLines with a space and save it as report.
Decisions & LoopsIf failures isn't emptyIf failures isn't empty
Yes
TextJoin failures with ; and save it as problemList.Join failures with ; and save it as problemList.
Decisions & LoopsStop and report a problem: report Needs attention: problemList.Stop and report a problem: report Needs attention: problemList.
No
No steps
Decisions & LoopsFinish the run: report.Finish the run: report.