TL;DR
You can set up a system that pulls your KPIs from a spreadsheet, fills an email template with real numbers, and sends your investor update automatically on the first of every month. Initial setup takes 3-4 hours of focused work. The core tools are Google Sheets, Make, and either Gmail or Mailchimp.
What You Need Before You Start
- Google account (free tier) with access to Google Sheets and Google Docs
- Make account (free tier supports 1,000 operations per month, enough for monthly sends to up to 150 investors)
- Mailchimp account free tier, or a Google Workspace Gmail address for sending
- ChartMogul free trial (optional, covers up to $10k MRR if you use Stripe for revenue tracking)
- Notion or Google Docs to draft and store your email template
- Your investor email list as a spreadsheet column, 5-150 addresses
- A working list of the 6-10 KPIs you track every month
- 3-4 hours of setup time and about 15 minutes each month to review before sending
Step 1: Define Your Update Structure and Placeholder Tokens
Before touching any tool, decide exactly what your update needs to say. A reliable investor update covers six areas: a key metrics snapshot, highlights from the month, what went wrong, what you need from investors, a financial summary, and a look-ahead for next month.
Open a Google Doc and draft your template using double-curly-brace tokens wherever a real number will go. For example:
MRR this month: {{mrr}}
MoM growth: {{mrr_growth_pct}}%
Active customers: {{active_customers}}
Cash in bank: {{cash_balance}}
Runway: {{runway_months}} months
Name every token exactly as you plan to name the corresponding column in your spreadsheet. Consistency here prevents broken lookups later. Keep the overall template between 400 and 600 words. Investors read dozens of updates each month and a tight, structured one gets read more than a long narrative one. You can find example formats at /investor-update-templates/.
You should now see: a Google Doc with a six-section structure and at least 6-8 placeholder tokens in {{snake_case}} format.
Step 2: Build Your KPI Tracker in Google Sheets
Create a new Google Sheet with two tabs: monthly_data and config.
On monthly_data, add one row per month. The first column is month in YYYY-MM format (for example 2026-05). Each subsequent column header must match your token names from Step 1, exactly, without the curly braces:
| month | mrr | mrr_growth_pct | active_customers | cash_balance | runway_months |
|---|---|---|---|---|---|
| 2026-04 | 12400 | 8.3 | 94 | 215000 | 17 |
| 2026-05 | 13200 | 6.5 | 101 | 198000 | 15 |
On the config tab, put investor email addresses in column A and first names in column B. Add a column C called active with TRUE or FALSE so you can easily exclude people who have left your cap table.
Fill in at least two months of historical data before moving on. One row breaks the “fetch the latest row” logic you will build in Make.
You should now see: a Google Sheet with two complete data rows, correct column headers, and a config tab with at least three test email addresses.
Step 3: Connect Your Revenue Data Source
If you track revenue manually, fill in the sheet yourself each month and skip to Step 4.
If you use Stripe, connect ChartMogul to your Stripe account and use Google Apps Script to pull MRR into your sheet automatically. Go to Extensions > Apps Script in your Google Sheet and paste this:
function fetchMRRFromChartMogul() {
const apiKey = 'your_chartmogul_api_key';
const startDate = '2026-05-01';
const endDate = '2026-05-31';
const url = `https://api.chartmogul.com/v1/metrics/mrr?start-date=${startDate}&end-date=${endDate}&interval=month`;
const response = UrlFetchApp.fetch(url, {
headers: {
'Authorization': 'Basic ' + Utilities.base64Encode(apiKey + ':')
}
});
const data = JSON.parse(response.getContentText());
const mrr = data.entries[0].mrr / 100; // ChartMogul stores amounts in cents
Logger.log('MRR: ' + mrr);
}
Run it once manually by clicking the play button. Do not proceed until the log shows a real number.
You should now see: your current MRR printed in the Apps Script execution log, matching the figure in your ChartMogul dashboard.
Step 4: Build Your Make Scenario
Log into Make and click Create a new scenario. Your scenario needs five modules connected in sequence:
- Schedule trigger set to Once a Month, on the 1st, at 9am your local timezone
- Google Sheets: Get a Row fetching the most recent row from
monthly_data - Google Docs: Get a Document Content fetching your template from Step 1
- Tools: Text Parser Replace (one per token) substituting each placeholder with live data
- Gmail or Mailchimp: Send an Email delivering the final message
Add each module by clicking the + icon on the canvas. When connecting Google Sheets, authenticate with your Google account when prompted. For the row lookup, you want the row with the highest row number. Use a Google Sheets: Search Rows module filtered by the current month using Make’s {{formatDate(now; "YYYY-MM")}} date function.
You should now see: five connected modules on the Make canvas, each showing a green checkmark after you click Run once in test mode.
Step 5: Replace Template Tokens with Live Data
Add a Tools: Text Parser Replace module for each token in your template. Chain them together so the output of each one feeds into the next.
Configure the first Replace module like this:
- Text: the document body from your Google Docs module
- Search:
{{mrr}} - Replace with: the
mrrcell value from your Google Sheets module
Then add another Replace module for {{mrr_growth_pct}}, chaining the output of the first into the Text field of the second, and so on for every token.
Doc body → Replace {{mrr}} → Replace {{mrr_growth_pct}} → Replace {{active_customers}} → Final body
Mismatched token names are the most common failure mode here. If your sheet column is named mrr_usd but your template says {{mrr}}, the replacement silently fails and investors receive an email with a raw placeholder in it. Spend five minutes here checking every name.
You should now see: the final Replace module’s output preview showing your email body with all placeholder text replaced by actual numbers.
Step 6: Loop Through Your Investor List
Add a Google Sheets: Search Rows module pointing at your config tab, filtered where column C active equals TRUE. Then add an Iterator module to process one investor at a time.
Your send module (Step 7) sits inside this loop. Each iteration fires once per investor, letting you personalize the greeting. Add a {{first_name}} token to your template and map column B from the config tab to it.
For under 30 recipients, Gmail works without issue. past 30, switch to Mailchimp’s transactional send to avoid Google flagging your account for bulk activity. Mailchimp’s free tier covers 500 contacts and 1,000 sends per month. Configure the Mailchimp: Send a Transactional Email module and map {{email}} from your config tab to the To field.
You should now see: the Iterator module showing one bundle per active investor row in your test run.
Step 7: Send and Log Every Message
Configure your send module with these fields:
- To:
{{email}}from your config tab - Subject:
[YourCompany] Investor Update, {{month}} - Body: the final replaced text from Step 5 (use HTML mode if your template has any formatting)
After the send module, add a Google Sheets: Add a Row module that writes to a send_log tab. Record the timestamp, recipient email, and subject line. This audit trail takes two minutes to set up and has saved founders from “did that go out?” panic more times than you can count.
Your send_log headers:
| timestamp | subject | status | |
|---|---|---|---|
| 2026-05-01 09:00 | jane@vc.com | [Acme] Update, 2026-05 | sent |
You should now see: a new row in send_log for each test recipient after a manual scenario run.
Step 8: Add a 24-Hour Review Buffer
Sending completely unreviewed updates to your cap table is a real risk. one bad API pull or a typo in your sheet and you have sent wrong numbers to everyone who matters to your fundraising.
Move your scenario trigger to the 28th of each month instead of the 1st. Instead of sending immediately, have Make post the composed email body to a private Slack channel using the Slack: Create a Message module, or write it to a draft_review tab in your sheet.
You review it on the 29th or 30th. if it looks right, flip a cell value in the sheet from FALSE to TRUE (for example, a cell named send_approved). A second, simpler Make scenario checks that cell on the 1st and only sends if it is TRUE.
This adds about 10 minutes per month and prevents embarrassing mistakes in front of investors. it is worth it.
You should now see: your full composed email appearing in Slack or your draft tab on the 28th, ready for a quick human review.
Step 9: Run a Full End-to-End Test
Before you let this scenario run unsupervised, replace every address in your config tab with your own email and run the full scenario manually.
Click Run once in Make and watch the modules execute left to right. Green checkmarks mean the module succeeded. Red error badges mean something failed, and Make will highlight the exact field that caused the problem.
Send yourself at least three test emails using three different data rows to confirm that tokens replace correctly, the subject line includes the right month, and the send_log updates accurately.
Once you are satisfied, restore your real investor list in the config tab, turn on the scenario, and set both schedule triggers to their correct dates. The Make dashboard shows you the next scheduled run time so you can verify before you close the tab.
You should now see: three emails in your own inbox with correct, different data values and three matching rows in your send_log tab.
Common Mistakes To Avoid
- Token name mismatches: if your sheet column is
mrr_usdbut your template says{{mrr}}, the replacement fails silently. Investors see the raw token. Name them identically everywhere. - Skipping the review buffer: the automation makes it easy to assume the data is correct. it is often not, especially in months when your metrics source had any kind of disruption. Always review.
- Using a personal Gmail for 40+ recipients: Google will eventually flag your account for bulk sending behavior. Use Google Workspace or switch to Mailchimp past 30 recipients.
- Seeding the sheet with only one month of data: your “get the latest row” logic in Make breaks if there is only one row. Always have at least two months of historical data before activating.
- Leaving the scenario timezone at UTC: if your Make account default is UTC and you are based in Singapore, your update goes out at 9am UTC, which is 5pm local time the day before. Set the timezone explicitly in the schedule trigger.
- Putting API keys in the Google Doc template: keep credentials in Make’s connection settings or a locked sheet tab. Never put them anywhere a shared viewer could accidentally see a draft.
When To Level Up
This setup works reliably for most early-stage founders with up to 150 investors and a standard metrics set. it starts to break down in a few specific situations.
If you need to generate individualized reports per investor where each person sees only their own portfolio performance, you cannot do that with a single shared template. you need custom logic that builds each email separately, which requires either a developer or a dedicated investor relations platform.
If your team has multiple contributors to the update and needs comment threads and approval workflows, the Google Doc plus Make approach becomes clunky. You could layer Notion into the drafting workflow, but that adds coordination overhead.
If you spend more than 30 minutes each month fixing data errors in the composed draft, the problem is upstream in your data pipeline, not in the send logic. Fix the source data before blaming the automation.
For a full comparison of reporting and automation tools suited to the next stage, visit /category/automation/. If you want to see what a proper startup reporting stack looks like beyond this, the breakdown at /best-tools-for-startup-reporting/ covers the options worth evaluating.
Frequently Asked Questions
Can I use this alongside a cap table tool like Carta?
Yes. Carta has its own update feature but it is limited in formatting and personalization. You can run this workflow in parallel and simply use your Carta investor list as the source for your config tab. The two systems do not conflict.
What happens if a data pull fails and Make sends wrong numbers?
The scenario will send whatever is in your sheet at the time. that is exactly why the 24-hour review buffer in Step 8 exists. Treat the draft review as a mandatory data quality check, not an optional skim.
Can I include charts or graphs in the email?
Embedding dynamic charts in HTML email is technically fragile and inconsistently rendered across email clients. The simpler approach is to link to a shared Google Sheet chart or a ChartMogul public dashboard URL in the email body rather than attempting to embed images.
How do I remove an investor who has left my cap table?
Set their active column in the config tab to FALSE. The Google Sheets Search Rows module in your scenario filters for TRUE only, so they are automatically excluded from the next send. No deletion needed.
Is storing investor emails in Google Sheets compliant with privacy regulations?
For legitimate business contacts with an existing relationship, this is generally acceptable under most frameworks. If you have EU-based investors, make sure your Google Workspace data region is configured for the EU and that you have documented legitimate interest as your legal basis. When uncertain, check with a lawyer familiar with startup compliance.
Bottom Line
The workflow is straightforward once you build it once: track your KPIs in Google Sheets, write a template with placeholder tokens in Google Docs, connect them through a Make scenario that replaces tokens with live data, loop through your investor list, and send each person a personalized email automatically on the first of every month. A 24-hour review buffer keeps you in control without adding significant manual work. On free tiers, this costs nothing for up to 50 investors per month. Most founders get the whole thing live in a single weekend session and then spend about 10-15 minutes each month reviewing the draft before approving the send. For the next step up in automation tooling, browse the full comparison at /category/automation/.