Auto-Respond to Gmail Emails with Google Apps Script

Whether you need an out-of-office reply, an automated acknowledgement for form submissions, or a keyword-triggered response, Apps Script gives you full control over Gmail auto-replies.

Basic auto-reply to unread emails

function autoReplyToUnread() { const query = 'is:unread subject:"Support Request"'; const threads = GmailApp.search(query); threads.forEach(thread => { const messages = thread.getMessages(); const lastMessage = messages[messages.length - 1]; // Don't reply to yourself if (lastMessage.getFrom().includes(Session.getActiveUser().getEmail())) return; lastMessage.reply( 'Thank you for reaching out! We have received your support request and will respond within 24 hours.\n\nBest regards,\nThe Support Team' ); thread.markRead(); Logger.log('Auto-replied to: ' + lastMessage.getSubject()); }); }

Reply with a personalised HTML email

function autoReplyHtml() { const query = 'is:unread label:enquiries'; const threads = GmailApp.search(query); threads.forEach(thread => { const lastMessage = thread.getMessages().pop(); const senderName = lastMessage.getFrom().split('<')[0].trim() || 'there'; const htmlBody = ` <p>Hi ${senderName},</p> <p>Thank you for your enquiry. We've received your message and our team will be in touch shortly.</p> <p>In the meantime, you might find these resources helpful:</p> <ul> <li><a href="https://example.com/faq">Frequently Asked Questions</a></li> <li><a href="https://example.com/docs">Documentation</a></li> </ul> <p>Best regards,<br>The Team</p> `; lastMessage.reply('', { htmlBody }); thread.markRead(); thread.addLabel(GmailApp.getUserLabelByName('auto-replied') || GmailApp.createLabel('auto-replied')); }); }

Avoid duplicate replies with label tracking

function smartAutoReply() { const REPLIED_LABEL = 'auto-replied'; const query = `is:unread subject:"Order Confirmation" -label:${REPLIED_LABEL}`; let label = GmailApp.getUserLabelByName(REPLIED_LABEL); if (!label) label = GmailApp.createLabel(REPLIED_LABEL); const threads = GmailApp.search(query); threads.forEach(thread => { const lastMessage = thread.getMessages().pop(); lastMessage.reply('Your order has been received and is being processed. Thank you!'); thread.addLabel(label); thread.markRead(); Logger.log('Replied to thread: ' + thread.getFirstMessageSubject()); }); }

Log auto-replies to a Google Sheet

function autoReplyAndLog() { const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(); if (sheet.getLastRow() === 0) { sheet.appendRow(['Timestamp', 'From', 'Subject', 'Status']); } const threads = GmailApp.search('is:unread subject:"Demo Request" -label:replied'); const label = GmailApp.getUserLabelByName('replied') || GmailApp.createLabel('replied'); threads.forEach(thread => { const msg = thread.getMessages().pop(); const from = msg.getFrom(); const subject = msg.getSubject(); try { msg.reply('Thanks for requesting a demo! We\'ll be in touch within 1 business day to schedule a time.'); thread.addLabel(label); thread.markRead(); sheet.appendRow([new Date(), from, subject, 'Replied']); } catch (e) { sheet.appendRow([new Date(), from, subject, 'Error: ' + e.message]); } }); }

Run every 15 minutes with a trigger

function createAutoReplyTrigger() { ScriptApp.newTrigger('smartAutoReply') .timeBased() .everyMinutes(15) .create(); }

Tips

  • Always use a label to track replied threads — without it, you'll send multiple replies to the same email.
  • GmailApp.search() returns a maximum of 500 threads. If you expect high volume, process in smaller batches.
  • lastMessage.getFrom() returns a string like "Name <[email protected]>" — parse it carefully when extracting the name.
  • Be cautious with overly broad search queries. Test in a dry-run mode (log without replying) before activating the trigger.