Google Sheets Apps Script Email Tutorial (Copy-Paste Ready)
Google Apps Script is the fastest way to add email functionality to your Google Sheet. You can send alerts when conditions are met, daily summary reports, or notifications when data changes.
This tutorial gives you copy-paste ready code for the most common email scenarios. No prior coding experience needed. Just paste, customize, and run.
Getting Started
Open any Google Sheet. Click Extensions > Apps Script. You will see a code editor with a blank function. Delete it. You are going to paste in code from this tutorial.
After pasting, click the play button (triangle) to test. Google will ask for permissions the first time. You need to allow access to your spreadsheet and Gmail.
Script 1: Simple Email from Spreadsheet Data
This reads your sheet and sends one email with the data.
function sendSimpleEmail() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var data = sheet.getDataRange().getValues();
var body = "Here is your data:
";
for (var i = 1; i < data.length; i++) {
body += data[i][0] + ": " + data[i][1] + "
";
}
MailApp.sendEmail("[email protected]", "Sheet Data Report", body);
}
This loops through every row (skipping the header) and includes column A and B values. Change column indexes and the email address to match your setup.
Script 2: Conditional Alert Email
Only sends an email when specific conditions are met.
function sendConditionalAlert() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var data = sheet.getDataRange().getValues();
var alerts = [];
for (var i = 1; i < data.length; i++) {
var name = data[i][0]; // Column A
var value = data[i][2]; // Column C
var status = data[i][3]; // Column D
if (value > 100 && status !== "Resolved") {
alerts.push(name + " - Value: " + value + " (Status: " + status + ")");
}
}
if (alerts.length > 0) {
MailApp.sendEmail(
"[email protected]",
"Alert: " + alerts.length + " items need attention",
"Items exceeding threshold:
" + alerts.join("
")
);
}
}
This checks if column C exceeds 100 AND column D is not "Resolved." Only matching rows trigger the alert. If nothing matches, no email is sent.
Script 3: Daily Summary Report
Sends a formatted daily summary of your data.
function sendDailySummary() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var data = sheet.getDataRange().getValues();
var totalItems = data.length - 1;
var completed = 0;
var pending = 0;
var overdue = 0;
var today = new Date();
today.setHours(0, 0, 0, 0);
for (var i = 1; i < data.length; i++) {
var status = data[i][3]; // Column D: status
var dueDate = new Date(data[i][2]); // Column C: due date
if (status === "Complete") {
completed++;
} else if (dueDate < today) {
overdue++;
} else {
pending++;
}
}
var body = "Daily Summary - " + today.toDateString() + "
"
+ "Total Items: " + totalItems + "
"
+ "Completed: " + completed + "
"
+ "Pending: " + pending + "
"
+ "Overdue: " + overdue + "
"
+ "Action needed: " + overdue + " overdue items require attention.";
MailApp.sendEmail("[email protected]", "Daily Summary: " + overdue + " overdue", body);
}
Script 4: HTML Formatted Email
Plain text emails work but look rough. Here is how to send formatted HTML emails:
function sendHtmlEmail() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var data = sheet.getDataRange().getValues();
var rows = "";
for (var i = 1; i < data.length; i++) {
var color = data[i][3] === "Overdue" ? "#ff4444" : "#ffffff";
rows += ""
+ "" + data[i][0] + " "
+ "" + data[i][1] + " "
+ "" + data[i][2] + " "
+ "" + data[i][3] + " "
+ " ";
}
var html = "Status Report
"
+ ""
+ ""
+ "Name "
+ "Amount "
+ "Due Date "
+ "Status "
+ rows + "
";
MailApp.sendEmail({
to: "[email protected]",
subject: "Status Report - " + new Date().toDateString(),
htmlBody: html
});
}
This creates a formatted table in the email with color-coded rows for overdue items. Much more readable than plain text.
Script 5: Send to Multiple Recipients
function sendToMultiple() {
var recipients = ["[email protected]", "[email protected]", "[email protected]"];
MailApp.sendEmail({
to: recipients.join(","),
subject: "Team Update",
body: "This is a team-wide notification from your Google Sheet."
});
}
Or send different emails to different people based on sheet data (like sending each tenant their own status):
function sendPersonalized() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Contacts");
var data = sheet.getDataRange().getValues();
for (var i = 1; i < data.length; i++) {
var name = data[i][0];
var email = data[i][1];
var amount = data[i][2];
MailApp.sendEmail(
email,
"Payment Reminder",
"Hi " + name + ",
Your balance is $" + amount
+ ". Please submit payment at your earliest convenience.
Thank you."
);
}
}
Setting Up Triggers
To run any of these scripts automatically:
1. In the Apps Script editor, click the clock icon (Triggers) in the left sidebar.
2. Click "Add Trigger" in the bottom right.
3. Choose your function name from the dropdown.
4. Set Event source to "Time-driven."
5. Choose frequency: "Day timer" for daily, "Hour timer" for hourly, "Week timer" for weekly.
6. Pick your time window.
7. Save.
The script now runs automatically on your schedule.
Error Handling
Add basic error handling to prevent silent failures:
function robustEmailScript() {
try {
// Your email logic here
var remaining = MailApp.getRemainingDailyQuota();
if (remaining < 10) {
Logger.log("Warning: Only " + remaining + " emails remaining today");
return;
}
// ... send emails ...
} catch (error) {
Logger.log("Script error: " + error.toString());
// Optionally email yourself about the error
MailApp.sendEmail(
"[email protected]",
"Script Error Alert",
"Your Google Sheets email script encountered an error:
" + error.toString()
);
}
}
This checks your daily email quota before sending and catches any errors. If something goes wrong, it emails you about the failure instead of failing silently.
Important Limits
Daily email quota: Free Google accounts: 100 emails/day. Google Workspace accounts: 1,500/day. Check remaining with MailApp.getRemainingDailyQuota().
Execution time: Scripts time out after 6 minutes (free) or 30 minutes (Workspace). Keep loops efficient.
Trigger reliability: Time-driven triggers are not exact. A "7am-8am" trigger runs sometime in that window. Occasionally triggers skip entirely. Check monthly.
Or Skip the Code Entirely
Apps Script is powerful and free. But it requires maintenance. Scripts break when columns move. Triggers fail silently. Email quotas limit scale.
If you are building email alerts for something critical - like rent payments, financial deadlines, or maintenance tracking - and you do not want to maintain code, RentGuard handles it without any scripting. Connect your sheet, map your columns, get text and email alerts. $15/month.
For more Apps Script patterns, see email alerts in Google Sheets, send email when cell changes, and conditional notifications.
Stop missing late rent payments
RentGuard monitors your Google Sheet and alerts you when rent is overdue or maintenance is aging. No migration. 5 minute setup. 30 days free.
Start Free Monitoring →