Back to BlogAutomation

Automate Donation Receipts and Tracking (For Tax Compliance)

Save 37+ hours monthly with automated donation receipts-ensure IRS compliance and eliminate errors, so your team can focus on mission-critical work.

December 26, 2025
4 min read

Your nonprofit lost 37 hours in January to donation receipt errors-37 hours your team could’ve spent on mission-critical work. All because a misplaced date voided three $250+ acknowledgments. The IRS doesn’t forgive mistakes. No valid receipt? No tax deduction. Do this manually, and you’ll cap out at 100 donations a month.

Stop Typing. Start Automating.

Manual receipting burns 8-10 hours per 100 donations: export Stripe data, paste into Sheets, generate PDFs in Canva, email one by one, update YTD totals. One typo in donor ID or date? IRS compliance fails.

The IRS requires written acknowledgment for donations ≥$250. Your receipt must include:

  • Org legal name and EIN
  • Donor name and address
  • Date and amount
  • Statement: “No goods or services were provided in exchange, except for intangible religious benefits” (if true)

Miss one item, the deduction fails.

Automate IRS Receipts in 60 Minutes

Use Google Apps Script to connect Stripe or PayPal to Sheets. On new donation, it auto-fills a Docs template, exports PDF, emails receipt within an hour, and updates YTD totals.

The Code: PDF Generator & Emailer

This script takes a row from Google Sheets, fills a Google Doc template, converts it to PDF, and emails it.

1. Setup Your Template

Create a Google Doc. Add placeholders like {{Name}}, {{Amount}}, {{Date}}. Copy the Header ID from the URL (the string between /d/ and /edit).

2. The Script

// CONFIGURATION
const CONFIG = {
  TEMPLATE_ID: 'YOUR_DOC_TEMPLATE_ID_HERE',
  FOLDER_ID: 'YOUR_DESTINATION_FOLDER_ID_HERE', // Where to save PDFs
  SHEET_NAME: 'Donations',
  ORG_NAME: 'Acme Nonprofit',
  ORG_EIN: '12-3456789'
};
 
function processDonations() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(CONFIG.SHEET_NAME);
  const dataRange = sheet.getDataRange();
  const data = dataRange.getValues();
  const headers = data[0];
  
  // Column Mapping (adjust based on your sheet)
  const COL = {
    EMAIL: headers.indexOf('Email'),
    NAME: headers.indexOf('Donor Name'),
    AMOUNT: headers.indexOf('Amount'),
    DATE: headers.indexOf('Date'),
    STATUS: headers.indexOf('Receipt Status')
  };
 
  // Iterate rows
  for (let i = 1; i < data.length; i++) {
    const row = data[i];
    const status = row[COL.STATUS];
    
    // Skip if already sent
    if (status === 'SENT') continue;
    
    // Check Quota
    if (MailApp.getRemainingDailyQuota() < 1) break;
 
    try {
      const pdfFile = createReceiptPdf(row, COL);
      sendEmail(row[COL.EMAIL], pdfFile, row[COL.NAME]);
      
      // Update Status
      sheet.getRange(i + 1, COL.STATUS + 1).setValue('SENT');
      sheet.getRange(i + 1, COL.STATUS + 2).setValue(new Date()); // Timestamp column
      
    } catch (e) {
      console.error(`Error row ${i + 1}: ${e.message}`);
      sheet.getRange(i + 1, COL.STATUS + 1).setValue('ERROR: ' + e.message);
    }
  }
}
 
function createReceiptPdf(row, colMap) {
  const templateFile = DriveApp.getFileById(CONFIG.TEMPLATE_ID);
  const folder = DriveApp.getFolderById(CONFIG.FOLDER_ID);
  
  // Make a temporary copy of the template
  const tempFile = templateFile.makeCopy(`Receipt_${row[colMap.NAME]}`, folder);
  const tempDoc = DocumentApp.openById(tempFile.getId());
  const body = tempDoc.getBody();
  
  // Replace placeholders
  body.replaceText('{{Name}}', row[colMap.NAME]);
  body.replaceText('{{Amount}}', '$' + parseFloat(row[colMap.AMOUNT]).toFixed(2));
  body.replaceText('{{Date}}', formatDate(row[colMap.DATE]));
  body.replaceText('{{OrgName}}', CONFIG.ORG_NAME);
  body.replaceText('{{EIN}}', CONFIG.ORG_EIN);
  
  tempDoc.saveAndClose();
  
  // Convert to PDF
  const pdfContent = tempFile.getAs(MimeType.PDF);
  const pdfFile = folder.createFile(pdfContent).setName(`Receipt - ${row[colMap.NAME]}.pdf`);
  
  // Delete temp doc
  tempFile.setTrashed(true);
  
  return pdfFile;
}
 
function sendEmail(email, pdf, name) {
  MailApp.sendEmail({
    to: email,
    subject: `Your Donation Receipt - ${CONFIG.ORG_NAME}`,
    body: `Hi ${name},\n\nThank you for your generous donation. Please find your tax receipt attached.\n\nSincerely,\n${CONFIG.ORG_NAME}`,
    attachments: [pdf]
  });
}
 
function formatDate(date) {
  return Utilities.formatDate(new Date(date), Session.getScriptTimeZone(), "MM/dd/yyyy");
}

Implementing Year-End Totals

Instead of scrambling in January, add a function to calculate YTD totals instantly.

function updateYTD(email, amount) {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Donors");
  // Logic to find donor row and add amount to YTD column
  // (See full example in our repo or book a call for the complete CRM kit)
}

Build vs. Buy: Why DIY Wins Under 5K Donations/Year

Factor Build (Apps Script) Buy (SaaS)
Cost $0 (Google Workspace) $50-300/month
Setup Time 60-90 minutes 1-2 weeks
Control Full data ownership Vendor lock-in
Compliance You control IRS language Generic templates

Process fewer than 5,000 donations a year? Build it. You keep your data. SaaS only makes sense for donor portals or complex recurring logic.

Reclaim 150+ Hours a Year

  • Automate IRS receipts in 60 minutes-no backend
  • Enforce exact IRS language-zero guesswork
  • Catch errors before they trigger audits

Book a call, running by Friday. 30-day warranty.

Related Industry Guides

Automate donation tracking with Google Workspace. Record donations, generate receipts, and create financial reports automatically.
Automate donor management with Google Workspace. Track donations, send thank-you letters, and manage donor communications efficiently.
Automate event management with Google Workspace. Handle registrations, send reminders, and track attendance automatically.
Automate grant reporting with Google Workspace. Track expenses, generate reports, and ensure compliance automatically.

Need a Custom Automation Solution?

We specialize in building tailored Google Workspace automations for businesses of all sizes. Let us help you eliminate repetitive tasks and streamline your workflows.

nonprofit automationGoogle Apps ScriptApps Script automationGoogle Sheetsemail automationdocument automationprocess automationmanual task elimination