You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:修复Google Apps Script生日自动邮件发送问题

修复生日自动邮件Google Apps Script脚本(日期识别失效问题)

问题背景

脚本无法识别Google Sheets中的生日日期,被标记为无效导致邮件无法发送。表格结构:

  • B列:收件人姓名
  • E列:生日日期
  • H列:客户邮箱
    数据从第3行开始(首行数据对应B3、E3、H3)

修复后的完整代码

function createBirthdayEmailTrigger() {
  // 删除现有触发器避免重复
  const triggers = ScriptApp.getProjectTriggers();
  triggers.forEach(trigger => ScriptApp.deleteTrigger(trigger));
  
  // 创建每日10AM运行的触发器(纽约时区)
  ScriptApp.newTrigger("sendBirthdayEmails")
    .timeBased()
    .everyDays(1)
    .atHour(9)
    .nearMinute(11)
    .inTimezone("America/New_York")
    .create();
  
  Logger.log('触发器已创建,每日10AM运行');
}

function sendBirthdayEmails() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CLIENTS HEALTH");
  if (!sheet) {
    Logger.log('未找到目标工作表');
    return;
  }

  const lastRow = sheet.getLastRow();
  // 仅获取需要的B、E、H列数据,减少冗余
  const range = sheet.getRange(3, 2, lastRow - 2, 7);
  const data = range.getValues();

  const timezone = "America/New_York";
  const today = Utilities.formatDate(new Date(), timezone, "MM-dd");
  Logger.log('今日日期(MM-dd):' + today);

  for (const row of data) {
    const name = row[0]?.trim();
    const birthDateRaw = row[3]; // E列对应数组索引3
    const email = row[6]?.trim(); // H列对应数组索引6

    // 提前过滤无效数据
    if (!name || !email || !email.includes("@")) {
      Logger.log(`跳过无效数据:姓名/邮箱为空或无效 - ${name}`);
      continue;
    }

    // 兼容Sheet中的Date对象和文本格式日期
    let birthDate;
    if (birthDateRaw instanceof Date) {
      birthDate = birthDateRaw;
    } else if (typeof birthDateRaw === 'string' && birthDateRaw.trim()) {
      birthDate = new Date(birthDateRaw);
    } else {
      Logger.log(`无效生日日期:${name} - ${birthDateRaw}`);
      continue;
    }

    // 验证日期有效性
    if (isNaN(birthDate.getTime())) {
      Logger.log(`无法解析生日日期:${name} - ${birthDateRaw}`);
      continue;
    }

    const birthDateFormatted = Utilities.formatDate(birthDate, timezone, "MM-dd");
    Logger.log(`检查客户:${name},生日:${birthDateFormatted}`);

    if (birthDateFormatted === today) {
      Logger.log(`准备发送生日邮件至:${email}`);

      const subject = "Happy Birthday";
      const body = `
        <img src="https://drive.google.com/uc?export=view&id=1QcsC_sqhl8Nt7BgNy98GdQisFygvkzW4" alt="Birthday Image" style="width:900px;height:600px;display:block;margin:auto;">
        <p style="font-family: 'Brush Script MT', cursive, Arial, sans-serif; font-size: 42px; color: red; text-align: center;">
          Happy Birthday, 🎂🎂 ${name} 🎈🎈!
        </p>
      `;

      try {
        MailApp.sendEmail({
          to: email,
          subject: subject,
          htmlBody: body
        });
        Logger.log(`邮件发送成功:${email}`);
      } catch (e) {
        Logger.log(`邮件发送失败:${email} - ${e.message}`);
      }
    } else {
      Logger.log(`今日非${name}的生日`);
    }
  }
}

关键修复点

  • 修正列索引错误:原代码中邮箱列(H)和生日列(E)的数组索引对应错误,已调整为正确的索引(H列→索引6,E列→索引3)
  • 日期兼容处理:区分Sheet中存储的Date对象和文本格式日期,避免直接解析日期对象导致的失效问题
  • 提前过滤无效数据:增加姓名、邮箱空值/无效值的提前检查,减少不必要的日志和处理
  • 明确时区设置:给触发器添加时区参数,避免跨时区导致的运行时间偏差
  • 范围优化:仅获取必要的B、E、H列数据,减少数据量和无关列干扰

内容的提问来源于stack exchange,提问作者AmateurCoder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 11:24:53