Gmail search and labels
GmailApp.search("from:billing@x.com is:unread") returns matching threads (newest first, up to 500); thread.getMessages() gives the messages with getSubject(), getFrom(), getDate(), getPlainBody() and getAttachments(). Labels: GmailApp.getUserLabelByName("Invoices") or createLabel, then thread.addLabel(label). Use the same search operators as the Gmail search box.
Syntax
GmailApp.search(query, start, max) | thread.getMessages() | thread.addLabel(label) | message.markRead()| Part | What it is |
|---|---|
query | Gmail search syntax: from:, to:, subject:, has:attachment, newer_than:7d, label:, is:unread |
start, max | Paging: offset and number of threads (max 500 per call) |
GmailApp.getUserLabelByName(name) | Existing label or null; GmailApp.createLabel(name) makes one |
Examples
const threads = GmailApp.search("subject:invoice has:attachment newer_than:30d");
Logger.log(threads.length);Result: Number of matching threads, for example 12
const sheet = SpreadsheetApp.getActiveSheet();
const rows = [];
GmailApp.search("is:unread label:inbox", 0, 50).forEach(t => {
t.getMessages().forEach(m => rows.push([m.getDate(), m.getFrom(), m.getSubject()]));
});
if (rows.length) sheet.getRange(sheet.getLastRow() + 1, 1, rows.length, 3).setValues(rows);Result: Date, sender and subject of unread inbox messages appended to the sheet
const label = GmailApp.getUserLabelByName("Invoices") || GmailApp.createLabel("Invoices");
GmailApp.search("from:billing@example.com -label:Invoices").forEach(t => {
t.addLabel(label).markRead().moveToArchive();
});Result: Billing emails labeled Invoices, marked read and archived
const folder = DriveApp.getFolderById("1Fo...");
GmailApp.search("has:attachment filename:pdf newer_than:1d").forEach(t => {
t.getMessages().forEach(m => m.getAttachments().forEach(a => folder.createFile(a)));
});Result: Every PDF attachment from the last day saved into the Drive folder
Common mistakes
- The search returns nothing although Gmail shows results: a label name with spaces needs quotes or hyphens (label:my-label), and Apps Script searches all mail unless you add in:inbox.
- The script runs out of time on a big mailbox: page with start and max, limit with newer_than, and record the last processed date in PropertiesService.
- getBody returns HTML with tags: use getPlainBody for text, or strip tags before writing to a sheet.
- Threads are relabeled on every run: add -label:Name to the query so already processed threads are excluded.
Practice Gmail search and labels
These drills check your answer on live data, free, no account needed.
- Group by a fieldReturn an object that maps each value of `item[key]` to the array of items with that value, in their original order. Values become object keys, so the number 2 becomes the key `"2"`. Keys are case-sensitive: `"Paid"` and `"paid"` are different groups.
- Parse a query stringParse a URL query string such as `"?page=2&tag=js&tag=web"` into an object of strings. The leading `?` is optional. `+` means a space and `%XX` escapes are decoded. A key without `=` gets `""`. Only the first `=` separates key from value. Empty pieces (as in `a=1&&b=2`) are skipped. A key that appears more than once maps to an array of its values in order.
- Make a URL slugTurn a title into a URL slug: lowercase, accents removed (é becomes e), and every run of characters that are not a to z or 0 to 9 replaced by a single hyphen. No hyphen at the start or end. Characters with no plain-letter form, such as 日本, are dropped.
Questions
Can I search a shared or delegated mailbox?
No. GmailApp only works with the mailbox of the account running the script. For another mailbox, the script must run from that account or that account must forward the mail.
How do I get only the latest message in a thread?
const msgs = thread.getMessages(); const last = msgs[msgs.length - 1];
Related
- Send email from a sheetSend email from Google Sheets with Apps Script: MailApp.sendEmail and GmailApp.sendEmail with HTML body, cc and attachments, loop a list of recipients, quota.
- List files in DriveList Google Drive files with Apps Script: get a folder by id, iterate getFiles with hasNext and next, read name, URL, size and dates, include subfolders.
- Time-driven triggersSchedule Google Apps Script with time-driven triggers: create them in the Triggers panel or with ScriptApp.newTrigger, run daily, hourly or weekly, delete.
- String methodsString methods you need in Apps Script: trim, toLowerCase, split, join, includes, startsWith, replace with regex, slice, padStart and template literals.
Previous: Send email from a sheetNext: Create a Google Doc from a template