Writes a personalised welcome email from each new client intake row, asks you to approve it, then sends it or drafts it.
Uses
Claude
Gmail
Google Sheets
Welcome new clients from their intake form
intakeSheetUrl to blank.Set intakeSheetUrl to blank.intakeTabName to blank.Set intakeTabName to blank.welcomedTabName to blank.Set welcomedTabName to blank.firmName to blank.Set firmName to blank.firmContext to blank.Set firmContext to blank.maxClientsPerRun to 10.Set maxClientsPerRun to 10.welcomedTabName in intakeSheetUrl. Save it as welcomedRead.Read column 'A' of welcomedTabName in intakeSheetUrl. Save it as welcomedRead.welcomedKeys to an empty list.Set welcomedKeys to an empty list.loggedAddress in welcomedRead.values:For each loggedAddress in welcomedRead.values:loggedErrorIf a step below fails, save the error as loggedErrorTry
loggedAddress in lowercase to the end of welcomedKeys and save it as welcomedKeys.Add loggedAddress in lowercase to the end of welcomedKeys and save it as welcomedKeys.On error
intakeSheetUrl. Save it as intake.Read the rows of intakeSheetUrl. Save it as intake.intake.headers is emptyIf intake.headers is emptyYes
Else if @intake.headers doesn't contain "Name" or @intake.h…
intake.headers with , and save it as foundHeaders.Join intake.headers with , and save it as foundHeaders.foundHeaders. Rename those header cells (for a Google Form, rename the questions) to Name, Email and Notes, then run it again.Stop and report a problem: The '@intakeTabName' tab needs columns named exactly Name, Email and Notes in its first row, but it has: foundHeaders. Rename those header cells (for a Google Form, rename the questions) to Name, Email and Notes, then run it again.Otherwise
No steps
welcomedThisRun to 0.Set welcomedThisRun to 0.stoppedAtLimit to false.Set stoppedAtLimit to false.failures to an empty list.Set failures to an empty list.row in intake.rows:For each row in intake.rows:welcomedThisRun is greater than or equal to maxClientsPerRunIf welcomedThisRun is greater than or equal to maxClientsPerRunYes
stoppedAtLimit to true.Change stoppedAtLimit to true.No
No steps
rowLabel to row row.row_number as text.Set rowLabel to row row.row_number as text.clientName to blank.Set clientName to blank.clientEmail to blank.Set clientEmail to blank.clientNotes to blank.Set clientNotes to blank.rowIsComplete to false.Set rowIsComplete to false.missingColumnIf a step below fails, save the error as missingColumnTry
row.Name and save it as clientName.Trim row.Name and save it as clientName.row.Email and save it as clientEmail.Trim row.Email and save it as clientEmail.row.Notes and save it as clientNotes.Trim row.Notes and save it as clientNotes.rowIsComplete to the length of clientName is greater than 0 and the length of clientEmail is greater than 0 and the length of clientNotes is greater than 0.Change rowIsComplete to the length of clientName is greater than 0 and the length of clientEmail is greater than 0 and the length of clientNotes is greater than 0.On error
rowLabel - the intake tab needs a Name, an Email and a Notes column.Show in the output: Skipping rowLabel - the intake tab needs a Name, an Email and a Notes column.rowIsComplete is noIf rowIsComplete is noYes
rowLabel - Name, Email and Notes must all be filled in before a welcome email can be written.Show in the output: Skipping rowLabel - Name, Email and Notes must all be filled in before a welcome email can be written.No
No steps
clientEmail is a valid email addressIf not clientEmail is a valid email addressYes
rowLabel - '@clientEmail' is not a valid email address.Show in the output: Skipping rowLabel - '@clientEmail' is not a valid email address.No
No steps
clientEmail lowercase and save it as emailKey.Make clientEmail lowercase and save it as emailKey.welcomedKeys contains emailKeyIf welcomedKeys contains emailKeyYes
clientEmail has already been welcomed - leaving rowLabel alone.Show in the output: clientEmail has already been welcomed - leaving rowLabel alone.No
No steps
welcomeErrorIf a step below fails, save the error as welcomeErrorTry
prompt to You are writing the body of a welcome email to a brand new client of a professional services firm. Write only the body of the email: no subject line, no placeholder brackets such as [Name], and nothing you cannot support from the details below. Greet the client by name, refer to what they asked for in their own terms, say what happens next, and sign off from the firm. Keep it under 200 words and do not invent dates, prices, or people.Set prompt to You are writing the body of a welcome email to a brand new client of a professional services firm. Write only the body of the email: no subject line, no placeholder brackets such as [Name], and nothing you cannot support from the details below. Greet the client by name, refer to what they asked for in their own terms, say what happens next, and sign off from the firm. Keep it under 200 words and do not invent dates, prices, or people.
About the firm:
firmName
firmContext
The new client:
Name: clientName
What they told us:
clientNotes.prompt. Save it as written.Ask Claude: prompt. Save it as written.
Maximum response length: 700written.response_text and save it as welcomeBody.Trim written.response_text and save it as welcomeBody.welcomeBody isn't emptyIf welcomeBody isn't emptyYes
subject to Welcome to firmName.Set subject to Welcome to firmName.welcomedTabName in intakeSheetUrl. Save it as welcomedNow.Read column 'A' of welcomedTabName in intakeSheetUrl. Save it as welcomedNow.welcomedNow.values contains emailKeyIf welcomedNow.values contains emailKeyYes
clientEmail is already waiting on another run's approval - leaving rowLabel to it.Show in the output: clientEmail is already waiting on another run's approval - leaving rowLabel to it.No
No steps
welcomedTabName in intakeSheetUrl.Add a row to welcomedTabName in intakeSheetUrl.emailKey to the end of welcomedKeys and save it as welcomedKeys.Add emailKey to the end of welcomedKeys and save it as welcomedKeys.welcomedThisRun.Add 1 to welcomedThisRun.clientName <clientEmail>? Save it as review.Request approval: Send this welcome email to clientName <clientEmail>? Save it as review.Approve and it goes to the client now, under your name. Reject it, or leave it, and it is saved as a Gmail draft for you to edit.
Subject: subject
welcomeBodyoutcome to blank.Set outcome to blank.review.approved is yesIf review.approved is yesYes
sendErrorIf a step below fails, save the error as sendErrorTry
clientEmail.Send an email to clientEmail.
Subject: subjectwelcomeBodyoutcome to Sent.Change outcome to Sent.On error
outcome to Send failed.Change outcome to Send failed.draftAfterSendErrorIf a step below fails, save the error as draftAfterSendErrorTry
clientEmail.Draft an email to clientEmail.
Subject: subjectwelcomeBodyoutcome to Send failed, saved as a draft.Change outcome to Send failed, saved as a draft.On error
No steps
clientName <clientEmail>: you approved the welcome email but it could not be sent (sendError.message). Recorded as '@outcome' on the '@welcomedTabName' tab. to the end of failures and save it as failures.Add clientName <clientEmail>: you approved the welcome email but it could not be sent (sendError.message). Recorded as '@outcome' on the '@welcomedTabName' tab. to the end of failures and save it as failures.No
draftErrorIf a step below fails, save the error as draftErrorTry
clientEmail.Draft an email to clientEmail.
Subject: subjectwelcomeBodyoutcome to Drafted.Change outcome to Drafted.On error
outcome to Draft failed.Change outcome to Draft failed.clientName <clientEmail>: the welcome email could not be saved as a draft (draftError.message). Recorded as 'Draft failed' on the '@welcomedTabName' tab. to the end of failures and save it as failures.Add clientName <clientEmail>: the welcome email could not be saved as a draft (draftError.message). Recorded as 'Draft failed' on the '@welcomedTabName' tab. to the end of failures and save it as failures.recordErrorIf a step below fails, save the error as recordErrorTry
welcomedTabName in intakeSheetUrl.Add a row to welcomedTabName in intakeSheetUrl.On error
clientName <clientEmail>: outcome, but that could not be written to the '@welcomedTabName' tab (recordError.message). to the end of failures and save it as failures.Add clientName <clientEmail>: outcome, but that could not be written to the '@welcomedTabName' tab (recordError.message). to the end of failures and save it as failures.No
clientName, so rowLabel is left for the next run.Show in the output: No welcome email was written for clientName, so rowLabel is left for the next run.On error
clientEmail: welcomeError.message. If they show as 'Awaiting approval' on the '@welcomedTabName' tab, delete that row to have them offered again. to the end of failures and save it as failures.Add Could not welcome clientEmail: welcomeError.message. If they show as 'Awaiting approval' on the '@welcomedTabName' tab, delete that row to have them offered again. to the end of failures and save it as failures.limitNote to blank.Set limitNote to blank.stoppedAtLimit is yesIf stoppedAtLimit is yesYes
This run asked about @maxClientsPerRun clients, the most 'maxClientsPerRun' allows; anyone else is offered on the next run. and save it as limitNote.Build the text This run asked about @maxClientsPerRun clients, the most 'maxClientsPerRun' allows; anyone else is offered on the next run. and save it as limitNote.No
No steps
failures isn't emptyIf failures isn't emptyYes
failures with a new line and save it as failureList.Join failures with a new line and save it as failureList.failureList@limitNote.No
No steps
welcomedThisRun@limitNote.Show in the output: Welcome emails handled this run: welcomedThisRun@limitNote.