Every Monday, emails anyone starting in the next week and tells the team in Slack who is joining.
Uses
Gmail
Google Sheets
Slack
Welcome next week's new starters
Every Monday at 07:00, your new starter roster is read, anyone whose start date falls within the next seven days gets a short welcome email, and your team channel in Slack is told who is joining, in what role and on which day, so nobody arrives to a room that was not expecting them.
The welcome email is written from the roster, not by AI: it greets the person by first name and gives their role and start date, so there is nothing to review and nothing to get confidently wrong. Lodol remembers who it has welcomed, so nobody is emailed or announced twice, even if you run it again by hand, and anyone further out is picked up on a later Monday. A hire with no email address is still announced to the team. If a start date can't be read, a column is missing or a message fails to send, the run is marked as failed and names the people affected, instead of looking like a quiet week.
You need Google Sheets, Gmail and Slack connected, the link to your roster, and the ID of the Slack channel for the announcements. The roster tab needs 'Name', 'Role', 'Email' and 'Start date' columns.
rosterUrl to blank.Set rosterUrl to blank.slackChannelId to blank.Set slackChannelId to blank.rosterTab to New hires.Set rosterTab to New hires.daysAhead to 7.Set daysAhead to 7.rosterUrl. Save it as roster.Read the rows of rosterUrl. Save it as roster.roster.headers is emptyIf roster.headers is emptyName, Role, Email, Start date] where roster.headers doesn't contain item and save it as missingColumns.Keep each item in [Name, Role, Email, Start date] where roster.headers doesn't contain item and save it as missingColumns.missingColumns isn't emptyIf missingColumns isn't emptymissingColumns with , and save it as missingList.Join missingColumns with , and save it as missingList.missingList. Its header row needs Name, Role, Email and Start date, spelled exactly like that. Nobody was welcomed or announced.Stop and report a problem: The '@rosterTab' tab is missing these columns: missingList. Its header row needs Name, Role, Email and Start date, spelled exactly like that. Nobody was welcomed or announced.todayDate.Get today's date and save it as todayDate.welcomedStore.Get the stored value 'welcomed_new_starters'. Save it as welcomedStore.done to an empty list.Set done to an empty list.welcomedStore.found is yesIf welcomedStore.found is yesdone to welcomedStore.value.Change done to welcomedStore.value.welcomed to an empty list.Set welcomed to an empty list.noEmail to an empty list.Set noEmail to an empty list.unreadable to an empty list.Set unreadable to an empty list.problems to an empty list.Set problems to an empty list.notes to an empty list.Set notes to an empty list.hire in roster.rows:For each hire in roster.rows:hire.Name is blank and hire["Start date"] is blankIf hire.Name is blank and hire["Start date"] is blankdaysUntil to 0.Set daysUntil to 0.dateErrorIf a step below fails, save the error as dateErrortodayDate to hire["Start date"] and save it as daysUntil.Count the days from todayDate to hire["Start date"] and save it as daysUntil.hire.Name (row hire.row_number) to the end of unreadable and save it as unreadable.Add hire.Name (row hire.row_number) to the end of unreadable and save it as unreadable.daysUntil is greater than or equal to 0 and daysUntil is less than or equal toโฆIf daysUntil is greater than or equal to 0 and daysUntil is less than or equal toโฆhire.Name and save it as hireName.Trim hire.Name and save it as hireName.hireName is blankIf hireName is blankhire.row_number) to the end of unreadable and save it as unreadable.Add a starter with no name (row hire.row_number) to the end of unreadable and save it as unreadable.hireName by a space and save it as nameParts.Split hireName by a space and save it as nameParts.hire["Start date"] readable as โMonday, November 2โ and save it as startDay.Make hire["Start date"] readable as โMonday, November 2โ and save it as startDay.hire["Start date"] readable as โ2026-11-02โ and save it as startKey.Make hire["Start date"] readable as โ2026-11-02โ and save it as startKey.@startKey email @hireName and save it as emailKey.Build the text @startKey email @hireName and save it as emailKey.@startKey team @hireName and save it as teamKey.Build the text @startKey team @hireName and save it as teamKey.hire.Email and save it as hireEmail.Trim hire.Email and save it as hireEmail.hireEmail is blank and done doesn't contain teamKeyIf hireEmail is blank and done doesn't contain teamKeyhireName to the end of noEmail and save it as noEmail.Add hireName to the end of noEmail and save it as noEmail.emailErrorIf a step below fails, save the error as emailErrorhireEmail.Send an email to hireEmail.
Subject: Welcome aboard, nameParts[0]Hi nameParts[0],
We are looking forward to your first day on startDay. You are joining us as hire.Role.
Someone will be in touch before then with your kit and your first-day details. If anything is unclear in the meantime, just reply to this message.
See you soon.emailKey to the end of done and save it as done.Add emailKey to the end of done and save it as done.hireName did not send (emailError.message). to the end of problems and save it as problems.Add The welcome email to hireName did not send (emailError.message). to the end of problems and save it as problems.done doesn't contain teamKeyIf done doesn't contain teamKeyslackErrorIf a step below fails, save the error as slackErrorslackChannelId.Send a message to slackChannelId.*Starting soon:* hireName joins as hire.Role on startDay - say hello when they arrive.teamKey to the end of done and save it as done.Add teamKey to the end of done and save it as done.hireName (startDay) to the end of welcomed and save it as welcomed.Add hireName (startDay) to the end of welcomed and save it as welcomed.hireName was not announced in Slack (slackError.message). to the end of problems and save it as problems.Add hireName was not announced in Slack (slackError.message). to the end of problems and save it as problems.done where the text before in item is greater than or equal to todayDate and save it as done.Keep each item in done where the text before in item is greater than or equal to todayDate and save it as done.saveErrorIf a step below fails, save the error as saveErrordone.Set the stored value 'welcomed_new_starters' to done.saveError.message), so running this again before their first day would welcome them a second time. to the end of problems and save it as problems.Add Lodol could not note who was welcomed (saveError.message), so running this again before their first day would welcome them a second time. to the end of problems and save it as problems.welcomed isn't emptyIf welcomed isn't emptywelcomed with , and save it as welcomedList.Join welcomed with , and save it as welcomedList.welcomedList. to the end of notes and save it as notes.Add Announced to the team: welcomedList. to the end of notes and save it as notes.noEmail isn't emptyIf noEmail isn't emptynoEmail with , and save it as noEmailList.Join noEmail with , and save it as noEmailList.noEmailList, so they were announced but not emailed. to the end of notes and save it as notes.Add No email address on the roster for noEmailList, so they were announced but not emailed. to the end of notes and save it as notes.unreadable isn't emptyIf unreadable isn't emptyunreadable with , and save it as unreadableList.Join unreadable with , and save it as unreadableList.unreadableList. Write it as a date such as 2026-11-02; until then they are not welcomed or announced. to the end of problems and save it as problems.Add Could not read the start date for unreadableList. Write it as a date such as 2026-11-02; until then they are not welcomed or announced. to the end of problems and save it as problems.notes with a space and save it as noteText.Join notes with a space and save it as noteText.problems isn't emptyIf problems isn't emptyproblems with a space and save it as problemList.Join problems with a space and save it as problemList.problemList noteText.Stop and report a problem: problemList noteText.notes is emptyIf notes is emptynoteText.Finish the run: noteText.