Reads each new purchase order email, looks its items up in your product list, and logs every line with name and price.
Uses
Claude
Gmail
Google Sheets
Extract purchase orders from Gmail
email.When an email arrives. Save it as email.spreadsheetUrl to blank.Set spreadsheetUrl to blank.productsTab to Products.Set productsTab to Products.ordersTab to Purchase orders.Set ordersTab to Purchase orders.email.body to 40000 characters and save it as emailText.Shorten email.body to 40000 characters and save it as emailText.cutNote to blank.Set cutNote to blank.email.body is greater than 40000If the length of email.body is greater than 40000Yes
cutNote to The email was too long to read in full, so only its first 40,000 characters were read: check no lines are missing..Change cutNote to The email was too long to read in full, so only its first 40,000 characters were read: check no lines are missing..No
No steps
aiReply to blank.Set aiReply to blank.aiErrorIf a step below fails, save the error as aiErrorTry
email.from
SUBJECT
email.subject
RECEIVED
email.date
EMAIL
emailText
Reply with one JSON object and nothing else - no code fence, no commentary before or after it. Use exactly these keys:
{is_purchase_order: true or false, certain: true or false, reason: ..., po_number: ..., customer: ..., order_date: ..., delivery_date: ..., note: ..., lines: [{sku: ..., description: ..., quantity: a number or null}]}
Rules:
- is_purchase_order: true only for a purchase order as described above. When it is false, put one short sentence in reason saying what the email is instead, and leave lines empty.
- certain: false when you are not sure the email is a purchase order. When in doubt, count it as one and set certain to false: a person can delete an extra row, but a missed order is lost. You cannot see attachments, so an email that says its order is attached - 'please find our PO attached', or only 'see attached' - counts as a purchase order with certain false and no lines.
- Copy every value exactly as the email writes it. Never guess, convert, total, or fill in a value that merely sounds right. A value the email does not give is an empty string.
- po_number: the buyer's purchase order number or order reference.
- customer: the company placing the order, or the person when no company is named.
- order_date and delivery_date: the date of the order and the delivery date the buyer asks for, as the email writes them. Leave order_date empty when the email itself gives no order date: the RECEIVED date above is when it arrived, not an order date.
- note: an empty string, unless the email says this order replaces, changes or repeats an earlier one - then say which in a few words, such as 'Replaces PO 4512'.
- lines: one entry per item ordered, in the email's order. sku is the product code, item number or part number as written, or an empty string when the line has none. description is the item's name or description as written. quantity is how many were ordered, as a JSON number with no units, no thousands separators and a dot for any decimals (1500, not 1,500; 2.5, not 2,5), reading the email's numbers the way the email itself writes them; null when the email does not say or you cannot tell.'. Save it as extraction.
Maximum response length: 8000aiReply to extraction.response_text.Change aiReply to extraction.response_text.On error
email.from, so nothing was logged: aiError.message.Stop and report a problem: The AI could not read the email '@email.subject' from email.from, so nothing was logged: aiError.message.reply, standing_note, and received and save it as order.Run Python code on reply, standing_note, and received and save it as order.order.problem isn't emptyIf order.problem isn't emptyYes
email.from: order.problem.Stop and report a problem: Could not log the email '@email.subject' from email.from: order.problem.No
No steps
order.is_purchase_order is noIf order.is_purchase_order is noYes
order.reason.Finish the run: Not a purchase order, so nothing was logged. order.reason.No
No steps
productRows to an empty list.Set productRows to an empty list.productColumns to an empty list.Set productColumns to an empty list.productListErrorIf a step below fails, save the error as productListErrorTry
spreadsheetUrl. Save it as productList.Read the rows of spreadsheetUrl. Save it as productList.productRows to productList.rows.Change productRows to productList.rows.productColumns to productList.headers.Change productColumns to productList.headers.On error
email.from was not logged: productListError.message.Stop and report a problem: Could not read the '@productsTab' tab, so the purchase order in the email '@email.subject' from email.from was not logged: productListError.message.productColumns doesn't contain SKUIf productColumns doesn't contain SKUYes
email.from was not logged. Give the tab the headers SKU, Product name and Unit price in its first row.Stop and report a problem: The '@productsTab' tab needs a column headed exactly 'SKU', so the purchase order in the email '@email.subject' from email.from was not logged. Give the tab the headers SKU, Product name and Unit price in its first row.No
No steps
productColumns doesn't contain Product nameIf productColumns doesn't contain Product nameYes
email.from was not logged. Give the tab the headers SKU, Product name and Unit price in its first row.Stop and report a problem: The '@productsTab' tab needs a column headed exactly 'Product name', so the purchase order in the email '@email.subject' from email.from was not logged. Give the tab the headers SKU, Product name and Unit price in its first row.No
No steps
productColumns doesn't contain Unit priceIf productColumns doesn't contain Unit priceYes
email.from was not logged. Give the tab the headers SKU, Product name and Unit price in its first row.Stop and report a problem: The '@productsTab' tab needs a column headed exactly 'Unit price', so the purchase order in the email '@email.subject' from email.from was not logged. Give the tab the headers SKU, Product name and Unit price in its first row.No
No steps
loggedIds to an empty list.Set loggedIds to an empty list.loggedIdsErrorIf a step below fails, save the error as loggedIdsErrorTry
ordersTab in spreadsheetUrl. Save it as loggedColumn.Read column 'M' of ordersTab in spreadsheetUrl. Save it as loggedColumn.loggedIds to loggedColumn.values.Change loggedIds to loggedColumn.values.On error
email.from is already logged, so its purchase order was not logged: loggedIdsError.message.Stop and report a problem: Could not read the '@ordersTab' tab to check whether the email '@email.subject' from email.from is already logged, so its purchase order was not logged: loggedIdsError.message.loggedIds contains email.email_idIf loggedIds contains email.email_idYes
email.from is in the '@ordersTab' tab under its Gmail message ID, so it was not logged again.Finish the run: Already logged: the email '@email.subject' from email.from is in the '@ordersTab' tab under its Gmail message ID, so it was not logged again.No
No steps
received to email.date.Set received to email.date.order.received_iso isn't blankIf order.received_iso isn't blankYes
T with in order.received_iso formatted as an ISO 8601 timestamp truncated to 16 characters using as the ellipsis and save it as received.Replace T with in order.received_iso formatted as an ISO 8601 timestamp truncated to 16 characters using as the ellipsis and save it as received.No
No steps
lines, skus, names, prices, order, received, and email_id and save it as priced.Run Python code on lines, skus, names, prices, order, received, and email_id and save it as priced.rowsToLog to priced.rows.Set rowsToLog to priced.rows.rowsToLog and save it as lineCount.Count the items in rowsToLog and save it as lineCount.linesWritten to 0.Set linesWritten to 0.logErrorIf a step below fails, save the error as logErrorTry
rowToAdd in rowsToLog:For each rowToAdd in rowsToLog:ordersTab in spreadsheetUrl. Save it as logged. Add a row to ordersTab in spreadsheetUrl. Save it as logged.linesWritten. Add 1 to linesWritten.On error
linesWritten of the lineCount lines of the purchase order in the email '@email.subject' from email.from were added to the '@ordersTab' tab: logError.message. Add the missing lines by hand: once any line of an email is in the tab, the workflow treats that email as logged and does not add the rest.Stop and report a problem: Google Sheets stopped after linesWritten of the lineCount lines of the purchase order in the email '@email.subject' from email.from were added to the '@ordersTab' tab: logError.message. Add the missing lines by hand: once any line of an email is in the tab, the workflow treats that email as logged and does not add the rest.lineCount line(s) from the email '@email.subject' to the '@ordersTab' tab.Finish the run: Logged lineCount line(s) from the email '@email.subject' to the '@ordersTab' tab.