Reads every document that arrives by email, logs a short summary of each in a Google Doc and emails you what came in.
Uses
Gmail
Google Docs
OpenAI
Summarise the documents people email you
Whenever new mail arrives, the messages matching your search that carry attachments and have not been read yet are swept, each PDF attached is read, a short summary of it is written into a running Google Doc, and one email listing what came in is sent to you at the end.
Every document is asked the same questions: what kind it is, who issued it, who it is for, its date, reference, what it asks of you, any deadline and any total. The answers come from the document itself, and a question it does not answer is recorded as not stated rather than filled in. The summary is written from those answers and nothing else, and offers no advice. Each message is labelled once its documents are logged and the sweep skips anything already labelled, so nothing is summarised twice, and nothing is emailed when nothing arrived.
Before the first run you need a Gmail search that finds the mail carrying documents, a Google Doc to keep the summaries in, and your own address for the note.
documentSearch to blank.Set documentSearch to blank.logDocumentUrl to blank.Set logDocumentUrl to blank.notifyEmail to blank.Set notifyEmail to blank.processedLabel to Document summaries.Set processedLabel to Document summaries.maxDocumentsPerRun to 5.Set maxDocumentsPerRun to 5.documentCap to maxDocumentsPerRun multiplied by 1.Set documentCap to maxDocumentsPerRun multiplied by 1.documentCap is greater than 25If documentCap is greater than 25documentCap is less than 1If documentCap is less than 1logDocumentId to blank.Set logDocumentId to blank.logDocumentUrl contains /d/ (ignoring case)If logDocumentUrl contains /d/ (ignoring case)logDocumentUrl split by /d/ split by / and save it as logDocumentId.Trim the first item of the last item of logDocumentUrl split by /d/ split by / and save it as logDocumentId.logDocumentId is emptyIf logDocumentId is empty@processedLabel'. Save it as found.List emails matching '@documentSearch has:attachment -label:@processedLabel'. Save it as found.summarisedCount to 0.Set summarisedCount to 0.digestLines to an empty list.Set digestLines to an empty list.message in found.emails:For each message in found.emails:summarisedCount is greater than or equal to documentCapIf summarisedCount is greater than or equal to documentCapmessageErrorIf a step below fails, save the error as messageErrormessageId to blank.Set messageId to blank.idErrorIf a step below fails, save the error as idErrormessage.id and save it as messageId.Trim message.id and save it as messageId.messageId is emptyIf messageId is emptySkipped a message Gmail returned without an id..Show in the output: Skipped a message Gmail returned without an id..rawFrom to blank.Set rawFrom to blank.fromErrorIf a step below fails, save the error as fromErrormessage.from and save it as rawFrom.Trim message.from and save it as rawFrom.senderAddress to rawFrom.Set senderAddress to rawFrom.rawFrom contains < (ignoring case)If rawFrom contains < (ignoring case)rawFrom split by < split by > and save it as senderAddress.Trim the first item of the last item of rawFrom split by < split by > and save it as senderAddress.senderAddress doesn't contain @ (ignoring case)If senderAddress doesn't contain @ (ignoring case)rawFrom.Show in the output: Skipped a message whose sender could not be read: rawFrom.subject to (no subject).Set subject to (no subject).subjectErrorIf a step below fails, save the error as subjectErrormessage.subject and save it as subjectText.Trim message.subject and save it as subjectText.subjectText isn't emptyIf subjectText isn't emptysubject to subjectText.Change subject to subjectText.latestId to blank.Set latestId to blank.latestErrorIf a step below fails, save the error as latestErrorsenderAddress'. Save it as latestFromSender.Find email matching 'from:senderAddress'. Save it as latestFromSender.latestFromSender.email.id and save it as latestId.Trim latestFromSender.email.id and save it as latestId.latestId is not messageIdIf latestId is not messageIdsenderAddress. Only a sender's newest message in the inbox can be opened, and a newer one has arrived - forward this message to yourself to have it read.Show in the output: Left alone: '@subject' from senderAddress. Only a sender's newest message in the inbox can be opened, and a newer one has arrived - forward this message to yourself to have it read.senderAddress. Save it as downloaded.Download the attachments on the latest email from senderAddress. Save it as downloaded.messageDocuments to 0.Set messageDocuments to 0.attachment in downloaded.documents:For each attachment in downloaded.documents:summarisedCount is greater than or equal to documentCap If summarisedCount is greater than or equal to documentCapfileName to blank. Set fileName to blank.nameError If a step below fails, save the error as nameErrorattachment.filename and save it as fileName.Trim attachment.filename and save it as fileName.attachmentLabel to (unnamed attachment). Set attachmentLabel to (unnamed attachment).fileName isn't empty If fileName isn't emptyattachmentLabel to fileName.Change attachmentLabel to fileName.fileName in lowercase doesn't end with .pdf (ignoring case) If fileName in lowercase doesn't end with .pdf (ignoring case)attachmentLabel: only PDF attachments are treated as documents.Show in the output: Skipped attachmentLabel: only PDF attachments are treated as documents.documentRef to blank. Set documentRef to blank.refError If a step below fails, save the error as refErrorattachment.document_ref and save it as documentRef.Trim attachment.document_ref and save it as documentRef.documentRef is empty If documentRef is emptyattachmentLabel; it was left alone.Show in the output: Could not open attachmentLabel; it was left alone.detailLines to an empty list. Set detailLines to an empty list.documentKind to not stated in the document. Set documentKind to not stated in the document.readError If a step below fails, save the error as readErrorreading.Run an AI agent: Read the attached document and pull out each of these fields, in this order: - What kind… and save it as reading.answer in reading.output.fields:For each answer in reading.output.fields:answerName to blank. Set answerName to blank.answerNameError If a step below fails, save the error as answerNameErroranswer.name and save it as answerName.Trim answer.name and save it as answerName.answerValue to blank. Set answerValue to blank.answerValueError If a step below fails, save the error as answerValueErroranswer.value and save it as answerValue.Trim answer.value and save it as answerValue.answerListErrorIf a step below fails, save the error as answerListErroranswer.value with , and save it as answerValue.Join answer.value with , and save it as answerValue.answerValue is empty If answerValue is emptyanswerValue to not stated in the document.Change answerValue to not stated in the document.documentKind to answerValue.Change documentKind to answerValue.answerName: answerValue truncated to 300 characters using … as the ellipsis to the end of detailLines and save it as detailLines. Add answerName: answerValue truncated to 300 characters using … as the ellipsis to the end of detailLines and save it as detailLines.detailLines is empty If detailLines is emptyattachmentLabel; nothing was written to the log and the mail was left alone.Show in the output: Could not read attachmentLabel; nothing was written to the log and the mail was left alone.summaryBrief to: Set summaryBrief to:Write a short plain summary of a document for the person who received it.
These are the only details that were read out of the document. Use nothing but these. Do not add anything, do not work anything out, and do not guess. Where a detail says it is not stated in the document, either say so plainly or leave it out - never fill it in.summaryRules to: Set summaryRules to:Write at most three sentences, describing only what the document says. Do not give advice, do not say what should be done about it, and do not comment on whether it is good, bad, risky or urgent.summaryText to blank. Set summaryText to blank.summaryError If a step below fails, save the error as summaryErrordetailLines joined by a new line plus summaryRules'. Save it as written.Ask OpenAI: '@summaryBrief plus detailLines joined by a new line plus summaryRules'. Save it as written.written.response_text and save it as summaryText.Trim written.response_text and save it as summaryText.summaryText is empty If summaryText is emptydetailLines with a new line and save it as summaryText.Join detailLines with a new line and save it as summaryText.attachmentLabel; the log has the document's own answers instead.Show in the output: No summary could be written for attachmentLabel; the log has the document's own answers instead.entryHeading to attachmentLabel - from senderAddress - the current date and time. Set entryHeading to attachmentLabel - from senderAddress - the current date and time.entryText to Set entryText to
entryHeading
summaryText
.logDocumentId. Add text to logDocumentId.entryTextsummarisedCount. Add 1 to summarisedCount.messageDocuments. Add 1 to messageDocuments.attachmentLabel from senderAddress - documentKind to the end of digestLines and save it as digestLines. Add attachmentLabel from senderAddress - documentKind to the end of digestLines and save it as digestLines.processedLabel to email messageId.Add label processedLabel to email messageId.messageDocuments is 0If messageDocuments is 0messageError as text.Show in the output: Could not read one document email: messageError as text.summarisedCount is greater than 0If summarisedCount is greater than 0digestBody to digestLines joined by a new lineSet digestBody to digestLines joined by a new line
The summaries are in your log: https://docs.google.com/document/d/@logDocumentId/edit.notifyEmail.Send an email to notifyEmail.
Subject: Documents read from your mail: summarisedCountdigestBodyNo new documents arrived to summarise..Show in the output: No new documents arrived to summarise..