<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>bulldo.gs — Apps Script &amp; Google Sheets recipes</title>
    <link>https://bulldo.gs/</link>
    <description>Plain-English Google Apps Script recipes for Sheets, Gmail, and Drive.</description>
    <language>en</language>
    <item>
      <title>Set a cell&apos;s number, date, or currency format with a script</title>
      <link>https://bulldo.gs/set-a-cell-number-format-with-a-script-in-google-sheets/</link>
      <guid isPermaLink="true">https://bulldo.gs/set-a-cell-number-format-with-a-script-in-google-sheets/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>Use Apps Script&apos;s setNumberFormat() to apply currency, date, percentage, and custom number patterns to any cell or range — without changing the underlying stored value.</description>
    </item>
    <item>
      <title>Send an email with an inline image in Gmail</title>
      <link>https://bulldo.gs/send-an-email-with-an-inline-image-in-gmail/</link>
      <guid isPermaLink="true">https://bulldo.gs/send-an-email-with-an-inline-image-in-gmail/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>How to embed an image directly in a Gmail message body using Apps Script&apos;s htmlBody and inlineImages options, so the image renders inline instead of appearing as an attachment.</description>
    </item>
    <item>
      <title>Create a time-driven trigger from code with ScriptApp</title>
      <link>https://bulldo.gs/create-a-time-driven-trigger-in-code-apps-script/</link>
      <guid isPermaLink="true">https://bulldo.gs/create-a-time-driven-trigger-in-code-apps-script/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>How to programmatically install an hourly (or daily) time-driven trigger in Apps Script using ScriptApp.newTrigger(), and how to avoid stacking duplicate triggers every time the installer runs.</description>
    </item>
    <item>
      <title>Unpivot a wide table into long rows in Google Sheets</title>
      <link>https://bulldo.gs/unpivot-a-wide-table-into-rows-in-google-sheets/</link>
      <guid isPermaLink="true">https://bulldo.gs/unpivot-a-wide-table-into-rows-in-google-sheets/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>Turn a wide pivot table into a tidy long format in Google Sheets using Apps Script — one output row per value, with columns for key, category, and value.</description>
    </item>
    <item>
      <title>Sort Drive files by created or modified date with Apps Script</title>
      <link>https://bulldo.gs/sort-drive-files-by-date-with-apps-script/</link>
      <guid isPermaLink="true">https://bulldo.gs/sort-drive-files-by-date-with-apps-script/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>DriveApp&apos;s file iterator returns files in no guaranteed order. Learn how to collect files into an array and sort them by getDateCreated() or getLastUpdated() before processing.</description>
    </item>
    <item>
      <title>Get the active user&apos;s email in Apps Script (and why it&apos;s sometimes blank)</title>
      <link>https://bulldo.gs/get-the-active-users-email-in-apps-script/</link>
      <guid isPermaLink="true">https://bulldo.gs/get-the-active-users-email-in-apps-script/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>Session.getActiveUser().getEmail() returns an empty string for cross-domain viewers and form respondents — learn exactly when it works, when it silently fails, and how to pull the real email from event objects instead.</description>
    </item>
    <item>
      <title>Copy files from one Drive folder to another with Apps Script</title>
      <link>https://bulldo.gs/copy-files-between-drive-folders-in-google-drive/</link>
      <guid isPermaLink="true">https://bulldo.gs/copy-files-between-drive-folders-in-google-drive/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>Use Apps Script to copy every file from one Google Drive folder into another — with a duplicate guard so re-running the script doesn&apos;t create a mess.</description>
    </item>
    <item>
      <title>Apply conditional formatting rules with a script in Google Sheets</title>
      <link>https://bulldo.gs/apply-conditional-formatting-with-a-script-in-google-sheets/</link>
      <guid isPermaLink="true">https://bulldo.gs/apply-conditional-formatting-with-a-script-in-google-sheets/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>How to build and attach a conditional formatting rule in Google Sheets using Apps Script — without wiping the existing rules already on the sheet.</description>
    </item>
    <item>
      <title>Delete all triggers for a project with Apps Script</title>
      <link>https://bulldo.gs/delete-all-triggers-for-a-project-apps-script/</link>
      <guid isPermaLink="true">https://bulldo.gs/delete-all-triggers-for-a-project-apps-script/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>How to delete every installable trigger in an Apps Script project using ScriptApp.getProjectTriggers() and deleteTrigger() — fixes the 20-trigger limit and clears duplicate triggers left by re-run setup functions.</description>
    </item>
    <item>
      <title>Pull data from a web page into Google Sheets with Apps Script</title>
      <link>https://bulldo.gs/scrape-a-web-page-into-google-sheets-with-apps-script/</link>
      <guid isPermaLink="true">https://bulldo.gs/scrape-a-web-page-into-google-sheets-with-apps-script/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>Use UrlFetchApp.fetch to grab raw HTML from any public URL, then extract a specific value with a targeted regex — no DOM parser needed, no external dependencies.</description>
    </item>
    <item>
      <title>Pause a script with Utilities.sleep (and when not to)</title>
      <link>https://bulldo.gs/pause-a-script-with-utilities-sleep-apps-script/</link>
      <guid isPermaLink="true">https://bulldo.gs/pause-a-script-with-utilities-sleep-apps-script/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>Utilities.sleep pauses Apps Script execution for milliseconds — useful for tight rate-limit gaps, but a long sleep burns your 6-minute execution budget. Learn when to use it and when to reach for a trigger instead.</description>
    </item>
    <item>
      <title>Use negative (NOT) search operators in Gmail with Apps Script</title>
      <link>https://bulldo.gs/use-negative-search-operators-in-gmail-apps-script/</link>
      <guid isPermaLink="true">https://bulldo.gs/use-negative-search-operators-in-gmail-apps-script/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>GmailApp.search() accepts the same query syntax as the Gmail search box, including minus-prefixed operators like -label:, -from:, and -is:starred to exclude threads from results.</description>
    </item>
    <item>
      <title>Check whether a cell contains a substring in Google Sheets</title>
      <link>https://bulldo.gs/check-if-a-cell-contains-text-in-google-sheets/</link>
      <guid isPermaLink="true">https://bulldo.gs/check-if-a-cell-contains-text-in-google-sheets/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>How to test if a cell contains a specific string in Google Sheets using Apps Script — covering single-cell checks with getValue() and the fast, correct pattern for whole-column scans with getValues().</description>
    </item>
    <item>
      <title>Keep a stable web app URL across deployments</title>
      <link>https://bulldo.gs/keep-a-stable-web-app-url-across-deployments-apps-script/</link>
      <guid isPermaLink="true">https://bulldo.gs/keep-a-stable-web-app-url-across-deployments-apps-script/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>Every time you hit &quot;New deployment&quot; in Apps Script you get a fresh /exec URL and everything pointing to the old one breaks. Use a named deployment and update its version instead.</description>
    </item>
    <item>
      <title>Build a direct download link for a Drive file with Apps Script</title>
      <link>https://bulldo.gs/get-a-direct-download-link-for-a-drive-file-apps-script/</link>
      <guid isPermaLink="true">https://bulldo.gs/get-a-direct-download-link-for-a-drive-file-apps-script/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>Learn how to generate a direct download link for a Google Drive file in Apps Script. The /view URL opens a preview; the download endpoint is https://drive.google.com/uc?export=download&amp;id=FILE_ID. This page shows you how to build that URL programmatically and share the file so the link works for others.</description>
    </item>
    <item>
      <title>Read a column by its header name, not its index</title>
      <link>https://bulldo.gs/get-a-column-by-its-header-name-in-google-sheets/</link>
      <guid isPermaLink="true">https://bulldo.gs/get-a-column-by-its-header-name-in-google-sheets/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>Stop hard-coding column numbers in Apps Script. Build a header map from row 1 so your script survives inserted columns without silently returning wrong data.</description>
    </item>
    <item>
      <title>Add a hyperlink to part of a cell&apos;s text in Google Sheets</title>
      <link>https://bulldo.gs/add-a-hyperlink-inside-cell-text-in-google-sheets/</link>
      <guid isPermaLink="true">https://bulldo.gs/add-a-hyperlink-inside-cell-text-in-google-sheets/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>Use Apps Script&apos;s RichTextValueBuilder to link a substring inside a cell — something the HYPERLINK() formula can&apos;t do.</description>
    </item>
    <item>
      <title>Convert Markdown text into a formatted Google Doc</title>
      <link>https://bulldo.gs/convert-markdown-to-a-google-doc-in-google-docs/</link>
      <guid isPermaLink="true">https://bulldo.gs/convert-markdown-to-a-google-doc-in-google-docs/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>A step-by-step Apps Script that parses Markdown headings and bold runs line-by-line and writes them to a Google Doc as real paragraph styles and bold text—no third-party libraries needed.</description>
    </item>
    <item>
      <title>Run a script when a new email arrives in Gmail</title>
      <link>https://bulldo.gs/run-a-script-when-a-new-email-arrives-in-gmail/</link>
      <guid isPermaLink="true">https://bulldo.gs/run-a-script-when-a-new-email-arrives-in-gmail/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>Gmail has no native push trigger for Apps Script. Learn the correct pattern: a time-driven trigger, an unread label search, and a processed-label guard to stay idempotent.</description>
    </item>
    <item>
      <title>Test an onEdit or onFormSubmit trigger without waiting for the event</title>
      <link>https://bulldo.gs/test-a-trigger-function-in-apps-script/</link>
      <guid isPermaLink="true">https://bulldo.gs/test-a-trigger-function-in-apps-script/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>Trigger functions receive an event object you can&apos;t produce by hand. Build a fake e with the exact fields your handler reads, then run it directly from the editor or a test function.</description>
    </item>
    <item>
      <title>Extract a Drive file ID from any share URL</title>
      <link>https://bulldo.gs/extract-a-drive-file-id-from-a-url-apps-script/</link>
      <guid isPermaLink="true">https://bulldo.gs/extract-a-drive-file-id-from-a-url-apps-script/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>One regex function that pulls the file ID out of every Drive URL shape — /d/ID/, ?id=ID, and open?id= — without brittle string splitting.</description>
    </item>
    <item>
      <title>Convert a date between timezones (with DST) in Google Sheets</title>
      <link>https://bulldo.gs/convert-between-timezones-in-google-sheets/</link>
      <guid isPermaLink="true">https://bulldo.gs/convert-between-timezones-in-google-sheets/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>Use Utilities.formatDate with an IANA timezone string to convert dates between timezones in Google Apps Script — DST-aware, no manual offset math required.</description>
    </item>
    <item>
      <title>Get driving distance between two addresses in Google Sheets</title>
      <link>https://bulldo.gs/get-driving-distance-between-two-addresses-in-google-sheets/</link>
      <guid isPermaLink="true">https://bulldo.gs/get-driving-distance-between-two-addresses-in-google-sheets/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>Use Google Apps Script and the Maps service to calculate driving distance between two addresses directly in a Sheets formula, with caching to stay inside the Maps quota.</description>
    </item>
    <item>
      <title>Persist global state across runs with PropertiesService</title>
      <link>https://bulldo.gs/use-properties-service-for-global-state-in-apps-script/</link>
      <guid isPermaLink="true">https://bulldo.gs/use-properties-service-for-global-state-in-apps-script/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>A top-level const in Apps Script resets to its initial value on every execution. Use PropertiesService to store a cursor, flag, or counter that survives between trigger runs.</description>
    </item>
    <item>
      <title>Generate a unique ID for each row in Google Sheets</title>
      <link>https://bulldo.gs/generate-a-unique-id-in-google-sheets/</link>
      <guid isPermaLink="true">https://bulldo.gs/generate-a-unique-id-in-google-sheets/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>Use Apps Script and Utilities.getUuid() to stamp a permanent, collision-proof UUID into every new row — written once, never overwritten on re-run.</description>
    </item>
    <item>
      <title>View logs and debug an Apps Script (where Logger.log actually goes)</title>
      <link>https://bulldo.gs/view-logs-and-debug-with-logger-in-apps-script/</link>
      <guid isPermaLink="true">https://bulldo.gs/view-logs-and-debug-with-logger-in-apps-script/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>Logger.log in Apps Script does not print to any console you can see while the script runs. Here is where to find the output, why console.log behaves differently, and how to read the Executions panel before the logs expire.</description>
    </item>
    <item>
      <title>Work with multiple ranges at once using getRangeList</title>
      <link>https://bulldo.gs/work-with-multiple-ranges-using-rangelist-in-google-sheets/</link>
      <guid isPermaLink="true">https://bulldo.gs/work-with-multiple-ranges-using-rangelist-in-google-sheets/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>getRangeList lets you clear, format, or check/uncheck several disjoint ranges in a single Apps Script call — but it cannot read cell values. Learn when to use it and what to reach for instead.</description>
    </item>
    <item>
      <title>Get a spreadsheet&apos;s ID from its URL or the active file</title>
      <link>https://bulldo.gs/get-a-spreadsheet-id-in-google-sheets/</link>
      <guid isPermaLink="true">https://bulldo.gs/get-a-spreadsheet-id-in-google-sheets/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>Two ways to pull a Google Sheets spreadsheet ID in Apps Script: getActiveSpreadsheet().getId() for the file you&apos;re in, and a one-line regex to extract it from any pasted /spreadsheets/d/&amp;lt;id&amp;gt;/edit URL.</description>
    </item>
    <item>
      <title>Force a custom function to recalculate in Google Sheets</title>
      <link>https://bulldo.gs/force-a-custom-function-to-recalculate-in-google-sheets/</link>
      <guid isPermaLink="true">https://bulldo.gs/force-a-custom-function-to-recalculate-in-google-sheets/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>Custom functions in Google Sheets cache their results and only re-run when their arguments change. Learn how to break that cache with a dummy NOW() argument or a time-driven trigger that writes a refresh token.</description>
    </item>
    <item>
      <title>Number the headings in a Google Doc with Apps Script</title>
      <link>https://bulldo.gs/number-the-headings-in-a-google-doc-in-google-docs/</link>
      <guid isPermaLink="true">https://bulldo.gs/number-the-headings-in-a-google-doc-in-google-docs/</guid>
      <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>
      <description>Walk the body paragraphs of a Google Doc, detect each HEADING type, and prepend an incrementing counter using Apps Script — since Docs has no built-in heading numbering.</description>
    </item>
    <item>
      <title>Create a form from spreadsheet data in Google Forms</title>
      <link>https://bulldo.gs/create-a-form-from-spreadsheet-data-in-google-forms/</link>
      <guid isPermaLink="true">https://bulldo.gs/create-a-form-from-spreadsheet-data-in-google-forms/</guid>
      <pubDate>Fri, 12 Jun 2026 00:00:00 GMT</pubDate>
      <description>Use Google Apps Script to read a spreadsheet and programmatically build a Google Form, including how to filter blank cells that cause setChoiceValues() to throw &apos;Invalid data updating form&apos;.</description>
    </item>
    <item>
      <title>Route responses to different sheets by answer in Google Forms</title>
      <link>https://bulldo.gs/route-responses-to-different-sheets-by-answer-in-google-forms/</link>
      <guid isPermaLink="true">https://bulldo.gs/route-responses-to-different-sheets-by-answer-in-google-forms/</guid>
      <pubDate>Fri, 12 Jun 2026 00:00:00 GMT</pubDate>
      <description>Use a form-bound onFormSubmit trigger and getItemResponses() to read answers and append rows to different sheets based on the value — without the undefined e.namedValues error that catches everyone the first time.</description>
    </item>
    <item>
      <title>Move uploaded files into a Drive folder in Google Forms</title>
      <link>https://bulldo.gs/move-uploaded-files-into-a-drive-folder-in-google-forms/</link>
      <guid isPermaLink="true">https://bulldo.gs/move-uploaded-files-into-a-drive-folder-in-google-forms/</guid>
      <pubDate>Fri, 12 Jun 2026 00:00:00 GMT</pubDate>
      <description>How to use Apps Script to automatically move file-upload responses from a Google Form into a specific Drive folder, using DriveApp.getFileById() to resolve the ID strings that itemResponse.getResponse() actually returns.</description>
    </item>
    <item>
      <title>Jump to a section based on an answer in Google Forms</title>
      <link>https://bulldo.gs/jump-to-a-section-based-on-an-answer-in-google-forms/</link>
      <guid isPermaLink="true">https://bulldo.gs/jump-to-a-section-based-on-an-answer-in-google-forms/</guid>
      <pubDate>Fri, 12 Jun 2026 00:00:00 GMT</pubDate>
      <description>Use Apps Script to wire Google Forms branching by attaching PageBreakItem targets to each choice — the one thing the UI editor makes tedious and scripts make repeatable.</description>
    </item>
    <item>
      <title>Grade a quiz with a script in Google Forms</title>
      <link>https://bulldo.gs/grade-a-quiz-with-a-script-in-google-forms/</link>
      <guid isPermaLink="true">https://bulldo.gs/grade-a-quiz-with-a-script-in-google-forms/</guid>
      <pubDate>Fri, 12 Jun 2026 00:00:00 GMT</pubDate>
      <description>How to auto-grade a Google Forms quiz with Apps Script using setScore(), setFeedback(), and the required submitGrades() call that actually persists the results.</description>
    </item>
    <item>
      <title>Insert a linked Sheets chart into a slide in Google Slides</title>
      <link>https://bulldo.gs/insert-a-linked-sheets-chart-into-a-slide-in-google-slides/</link>
      <guid isPermaLink="true">https://bulldo.gs/insert-a-linked-sheets-chart-into-a-slide-in-google-slides/</guid>
      <pubDate>Fri, 12 Jun 2026 00:00:00 GMT</pubDate>
      <description>Use Apps Script to insert a linked Sheets chart into a Google Slides presentation and keep it current with a refresh trigger — because insertSheetsChart() only captures the chart at insertion time.</description>
    </item>
    <item>
      <title>Sort slides alphabetically by title in Google Slides</title>
      <link>https://bulldo.gs/sort-slides-alphabetically-by-title-in-google-slides/</link>
      <guid isPermaLink="true">https://bulldo.gs/sort-slides-alphabetically-by-title-in-google-slides/</guid>
      <pubDate>Fri, 12 Jun 2026 00:00:00 GMT</pubDate>
      <description>Reorder Google Slides by title text using Apps Script. Covers the index-shift trap in Slide.move() and the correct pattern: sort handles in memory, then move in ascending order.</description>
    </item>
    <item>
      <title>Set speaker notes on every slide in Google Slides</title>
      <link>https://bulldo.gs/set-speaker-notes-on-every-slide-in-google-slides/</link>
      <guid isPermaLink="true">https://bulldo.gs/set-speaker-notes-on-every-slide-in-google-slides/</guid>
      <pubDate>Fri, 12 Jun 2026 00:00:00 GMT</pubDate>
      <description>How to read and write speaker notes on every slide in Google Slides using Apps Script — the NotesPage indirection that getShapes() silently skips.</description>
    </item>
    <item>
      <title>Export each slide as a PNG in Google Slides</title>
      <link>https://bulldo.gs/export-each-slide-as-a-png-in-google-slides/</link>
      <guid isPermaLink="true">https://bulldo.gs/export-each-slide-as-a-png-in-google-slides/</guid>
      <pubDate>Fri, 12 Jun 2026 00:00:00 GMT</pubDate>
      <description>SlidesApp has no built-in image export. Use the Advanced Slides Service (Slides.Presentations.Pages.getThumbnail) to fetch a per-page PNG blob immediately — the contentUrl expires in ~30 minutes, so UrlFetchApp it in the same execution.</description>
    </item>
    <item>
      <title>Generate certificates from a template in Google Slides</title>
      <link>https://bulldo.gs/generate-certificates-from-a-template-in-google-slides/</link>
      <guid isPermaLink="true">https://bulldo.gs/generate-certificates-from-a-template-in-google-slides/</guid>
      <pubDate>Fri, 12 Jun 2026 00:00:00 GMT</pubDate>
      <description>Use Apps Script to copy a Slides template once per row, replace placeholder text, then call saveAndClose() before exporting — skipping that flush is why your PDFs come out blank.</description>
    </item>
  </channel>
</rss>
