Eid Card Mail Automation
My first real automation project, self-taught from Google's own documentation and Stack Overflow, back before AI could write a line of it for me, and still the one I'm proudest of.
Google Sheets
Long before I called myself a Product Manager, I was the person at 10 Minute School (10MS) who'd rather spend a weekend writing a script than repeat the same manual task a fourth time. This is that project, and it's still the one I'm proudest of, not because it was complex, but because I built it entirely on my own, at a point where "just ask an AI" wasn't an option yet.
It started as a small, seasonal problem. Every year around Eid, 10MS HR put together a personalised Eid card for the team, and every year that meant designing each card and then emailing it out by hand, one inbox at a time. I approached HR and told them I could automate both halves of that job, generating the cards themselves (that's its own image-generation story) and getting them into every inbox without anyone touching Send more than once.
This is the story of that second half.
The Problem
- Sending a personalised card to every single person on the team meant either a slow, manual mail-merge in an email client, or opening a fresh compose window for each name, both error-prone at any real headcount
- There was no reliable way to loop over a list of names and drop each one into its own card and its own email without a developer sitting there doing it by hand
- And there was no AI to lean on. This was 2021–22, so the only path from "I think this is possible" to a working script was Google's own documentation and whatever Stack Overflow threads I could find that were close enough to adapt
The Approach
I built it in stages, each one solving the next problem the previous version exposed, rather than trying to design the finished thing up front.
First, just get an email out to everyone. The very first version did one
thing, loop over a list of addresses in a sheet and send the same message to all of them
through GmailApp. No personalisation, no attachment, just proof that a script
running from a spreadsheet could reliably reach every inbox on the list.
Then, make it personal. A card addressed to "Dear Employee" defeats the
point of a personalised Eid card. The second version pulled a Gmail draft as the template and
filled in {{Name}}-style tokens from each row of the sheet, so the subject and
body reached every person with their own name in the right place, not just their own address
in the To field. Working out the token-replacement and escaping logic without an AI to check
my regex against was genuinely the hardest part of this whole project, a lot of it traces
back to Google's own documented mail-merge example, but adapting it and getting the edge
cases right was Stack Overflow and trial and error, one failed test send at a time.
Then, attach the actual card. Once the image-generation side of the project could produce a finished card per person and drop it into Drive, the mailer needed to pick that file up and attach it automatically. The third version read a Drive link straight out of the sheet, pulled the file ID out of it, and attached the corresponding file to that person's email, so the whole pipeline, generate the card, then mail the card, could run without anyone touching a single attachment by hand.
Recently, CC and BCC, because another project needed it. The pattern didn't
stay a one-off. Years later, a different project needed the same mail-merge approach, but with
CC recipients, so I went back into this same script and added a CC column,
splitting and trimming a comma-separated list and passing it straight into
GmailApp.sendEmail alongside the existing recipient and attachment logic. BCC
follows the exact same pattern, one more column, one more split, one more field on the send
call. The version on the code page reflects that update.
The Outcome
- Zero manual sending, every employee's Eid card reached their inbox, personalised by name, from a single "Send Mail → Send Emails" click in the sheet
- Safe to re-run, an "Email Sent" column stamped with a timestamp per row meant running the script again never double-sent a card
- A pattern that outlived the project, the same script, drafts as templates, {{tokens}} filled from a sheet, attachments pulled from Drive, got reused years later and extended with CC support the moment another project needed it