Gmail Automation: The Complete Google Apps Script Guide (2025)

Google Apps Script is a powerful tool that allows you to create custom Gmail automations. With automation, you can eliminate tideous and routine tasks such as manually sorting and labeling hundreds of emais per day, and sending follow-up emails to customers or candidates.

This posts explains:

  • what is Google Apps Script
  • how to create your first Gmail automation script
  • 8 more powerful examples you can copy-paste
  • how to run and monitor your script
  • how to gain extra email productivity without coding at all

Apps Script Demystified

Google Apps Script is a cloud-based JavaScript platform that integrates seamlessly with Google Workspace. The script lives within your Google account, ready to automate all those mind-numbing tasks you secretly dread. No more copy-pasting, no more endless clicking—just pure unadulterated automation bliss.

Your First Gmail Automation: The “Out of Office” Upgrade

Let’s start with a classic: the out-of-office reply. But with a twist. Instead of a generic message, we’ll create a script that sends a personalized response based on the sender’s email address.

Setting Up Apps Script

  1. Access the Script Editor: Open your Gmail account. Click the grid icon at the top-right corner, go to Google Drive, and create a new Google Apps Script project by selecting New > Google Apps Script.

  2. Authorize the Script: Your script will require access to Gmail. When prompted, grant the necessary permissions.

  3. Write the Code: Use the editor to write custom scripts for your automation tasks. Here is the code for the “Out of Office” script. This script checks who emailed you and sends a tailored response. Pretty neat, right?

 1function autoReply() {
 2  // Get the current thread.
 3  let thread = GmailApp.currentThread()
 4  // Get the sender's email address.
 5  const sender = thread.getMessage(0).getFrom()
 6
 7  // Check if the sender is already in the 'Replied To' list.
 8  const labels = thread.getLabels()
 9  if (labels.some(label => label.getName() === 'Replied To')) {
10    return // Skip if already replied
11  }
12
13  const importantResponse = `
14    Thanks for your email!
15    I'm currently out of the office, but I'll get back to you as soon as I can.
16    In the meantime, please contact my colleague at colleague@example.com.`
17  const defaultResponse = `
18    Thanks for your email!
19    I'm currently out of the office and will respond upon my return.`
20
21  // Personalized responses.
22  var responses = {
23    "importantclient@example.com": importantResponse,
24    "default": defaultResponse
25  }
26
27  var replyMessage = responses[sender] || responses["default"]
28
29  // Send the personalized reply.
30  thread.reply(replyMessage)
31  // Add a label to avoid duplicate replies
32  thread.addLabel(GmailApp.createLabel('Replied To'))
33}

8 More Powerful Examples You Can Copy-Paste

Use OpenAI to summarize long emails in Gmail

 1function summarizeLongEmailsUsingOpenAI() {
 2  const apiKey = "your-openai-api-key" // Replace with your OpenAI API key
 3  const threads = GmailApp.search("is:unread")
 4
 5  threads.forEach(thread => {
 6    const message = thread.getMessages()[0]
 7    const emailBody = message.getPlainBody()
 8
 9    // OpenAI API URL
10    const openAiUrl = "https://api.openai.com/v1/completions"
11
12    // Request payload
13    const payload = {
14      model: "gpt-4o-mini",
15      prompt: `Summarize the following email:\n\n${emailBody}\n\nSummary:`,
16      temperature: 0.5
17    }
18
19    // Set up the API request
20    const options = {
21      method: "post",
22      contentType: "application/json",
23      payload: JSON.stringify(payload),
24      headers: {
25        Authorization: `Bearer ${apiKey}`
26      }
27    }
28
29    // Make the API request
30    try {
31      const response = UrlFetchApp.fetch(openAiUrl, options)
32      const jsonResponse = JSON.parse(response.getContentText())
33      const summary = jsonResponse.choices[0].text.trim()
34
35      // Reply to the thread but only send to yourself
36      thread.replyAll(
37        `Summary of the email:\n\n${summary}\n\n---\nAutomatically generated by AI`,
38        {
39          to: Session.getActiveUser().getEmail(), // Only send to yourself
40          noReply: true  // Don't include original recipients
41        }
42      )
43
44      message.markRead()
45
46      // Add a label to track summarized emails
47      const summaryLabel = GmailApp.createLabel('AI-Summarized')
48      thread.addLabel(summaryLabel)
49    } catch (error) {
50      Logger.log("Error summarizing email: " + error)
51    }
52  })
53}

Log complaints to a CRM

 1function logComplaintsToCRM() {
 2  const crmApiUrl = "https://api.crm.com/complaints"
 3  const threads = GmailApp.search("label:complaints")
 4
 5  threads.forEach(thread => {
 6    const message = thread.getMessages()[0]
 7    const payload = {
 8      customer: message.getFrom(),
 9      subject: message.getSubject(),
10      complaint: message.getPlainBody()
11    }
12
13    UrlFetchApp.fetch(crmApiUrl, {
14      method: "post",
15      contentType: "application/json",
16      payload: JSON.stringify(payload),
17      headers: { Authorization: `Bearer your-crm-api-key` }
18    })
19  })
20}

Auto-generate calendar events from emails with time mentions

 1function autoCreateCalendarEvents() {
 2  const threads = GmailApp.search("subject:(meeting OR schedule)")
 3  const calendar = CalendarApp.getDefaultCalendar()
 4
 5  threads.forEach(thread => {
 6    const message = thread.getMessages()[0]
 7    const body = message.getPlainBody()
 8    const timeMatch = body.match(/\d{4}-\d{2}-\d{2} \d{2}:\d{2}/) // Example: 2025-01-15 14:00
 9
10    if (timeMatch) {
11      const eventDate = new Date(timeMatch[0])
12      calendar.createEvent(message.getSubject(), eventDate, new Date(eventDate.getTime() + 60 * 60 * 1000)) // 1-hour event
13    }
14  })
15}

Send follow-up reminders automatically

 1function sendFollowUpReminders() {
 2  const labelName = "Follow-Up"
 3  const threads = GmailApp.getUserLabelByName(labelName).getThreads()
 4
 5  threads.forEach(thread => {
 6    const messages = thread.getMessages()
 7    const lastMessage = messages[messages.length - 1]
 8    if (!lastMessage.isInInbox()) {
 9      GmailApp.sendEmail(thread.getFirstMessageSubject(), "Follow-Up Reminder")
10    }
11  })
12}

Automatically resend unanswered emails

 1function resendUnansweredEmails() {
 2  const threads = GmailApp.search("label:sent newer_than:7d")
 3
 4  threads.forEach(thread => {
 5    const messages = thread.getMessages()
 6    const lastMessage = messages[messages.length - 1]
 7    if (lastMessage.isDraft() && !thread.hasStarredMessages()) {
 8      GmailApp.sendEmail(thread.getFirstMessageSubject(), lastMessage.getBody())
 9    }
10  })
11}

Slack notification when an important email is received

 1function notifySlackForImportantEmails() {
 2  const slackWebhookUrl = "https://hooks.slack.com/services/your/slack/webhook"
 3  const threads = GmailApp.search("label:important is:unread")
 4
 5  threads.forEach(thread => {
 6    const message = thread.getMessages()[0]
 7    const payload = {
 8      text: `New Important Email: ${message.getSubject()} from ${message.getFrom()}`
 9    }
10    UrlFetchApp.fetch(slackWebhookUrl, {
11      method: "post",
12      contentType: "application/json",
13      payload: JSON.stringify(payload)
14    })
15  })
16}

Forward specific emails to a different address

 1function forwardEmails() {
 2  const recipient = "assistant@example.com"
 3  const threads = GmailApp.search("label:important")
 4
 5  threads.forEach(thread => {
 6    const messages = thread.getMessages()
 7    messages.forEach(message => {
 8      GmailApp.sendEmail(recipient, message.getSubject(), message.getPlainBody())
 9    })
10  })
11}

Sync email attachments with Google Drive by category

 1function organizeAttachmentsByCategory() {
 2  const categories = ["Invoices", "Reports", "Contracts"]
 3  const parentFolderId = "your-parent-folder-id-in-google-drive"
 4
 5  // Ensure all category folders exist and get their IDs
 6  const folderIds = {}
 7  categories.forEach(category => {
 8    folderIds[category] = getOrCreateFolder(category, parentFolderId)
 9  })
10
11  // Process Gmail threads with attachments
12  const threads = GmailApp.search("has:attachment")
13  threads.forEach(thread => {
14    const message = thread.getMessages()[0]
15    const subject = message.getSubject()
16    const attachments = message.getAttachments()
17
18    // Match email subject to a category and move attachments
19    for (const category in folderIds) {
20      if (subject.includes(category)) {
21        const folder = DriveApp.getFolderById(folderIds[category])
22        attachments.forEach(attachment => folder.createFile(attachment))
23      }
24    }
25  })
26}
27
28// Helper function to get or create a folder by name under a parent folder
29function getOrCreateFolder(folderName, parentFolderId) {
30  const parentFolder = DriveApp.getFolderById(parentFolderId)
31  const folders = parentFolder.getFoldersByName(folderName)
32
33  // If the folder already exists, return its ID
34  if (folders.hasNext()) {
35    return folders.next().getId()
36  }
37
38  // Otherwise, create the folder and return the new ID
39  const newFolder = parentFolder.createFolder(folderName)
40  return newFolder.getId()
41}

Deploy and Monitor Your Script

Before deploying, run your script in the Apps Script editor to ensure it works as expected. Use the debug console to identify errors.

Then, set a trigger to automate the script. Go to Triggers in the Apps Script editor. Click Add Trigger and configure it.

If sharing is needed, publish the script as an add-on for others to install and use.

Use the Logger.log function to debug your script. Access logs under View > Logs in the Apps Script editor. You can also set up email notifications for errors. This way, you’re alerted when something goes wrong.

Coding Is Too Hard. How to Gain Email Productivity?

You are here probably because you are swamped by emails and are looking for every chance to save time.

TypeTab is the real answer. It will 10x your email productivity. It offers a drop-in replacement for gmail autocomplete but is context-aware and powered by the best AI models. No prompting. Just press Tab to accept AI suggestions. TypeTab works right in the gmail page. No more copy-paste or switching apps. TypeTab never sells or trains on your data. Take back your time—Think about your hourly salary and how much time you spend on emails.

Start your free trial at typetab.com, no credit card required.