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

Google Script邮件发送遇无效邮箱终止循环的解决咨询

问题解决方案

一、跳过无效邮箱,避免循环终止

1. 给sendEmail函数添加异常捕获与邮箱验证

原来的sendEmail函数遇到无效邮箱会抛出错误,而外层全局try-catch会直接终止整个循环。我们需要把异常捕获放到函数内部,同时提前验证邮箱格式,无效邮箱直接跳过并记录日志:

function sendEmail(lic_detalles){
  try {
    // 验证并过滤有效邮箱
    const validEmails = validateEmails([lic_detalles.dest_1, lic_detalles.dest_2]);
    if (validEmails.length === 0) {
      console.log(`行号${lic_detalles.numero}:无有效邮箱,跳过发送`);
      logError(`行号${lic_detalles.numero}:无有效邮箱,dest_1=${lic_detalles.dest_1}, dest_2=${lic_detalles.dest_2}`);
      return;
    }
    const emailList = validEmails.join(',');
    
    // 加载邮件模板并发送
    var templ = HtmlService.createTemplateFromFile('EmailTemplate');
    templ.lic_detalles = lic_detalles;
    var messagemail = templ.evaluate().getContent();
    MailApp.sendEmail({
      to: emailList,
      cc: emailList, // 可添加去重逻辑避免重复抄送
      subject: `${lic_detalles.cliente} SU LICENCIA VENCE EN ${lic_detalles.dias_rest} DIAS`,
      htmlBody: messagemail
    });
    console.log(`行号${lic_detalles.numero}:邮件发送成功`);
  } catch(e) {
    console.log(`行号${lic_detalles.numero}:邮件发送失败,错误:${e.message}`);
    logError(`行号${lic_detalles.numero}:邮件发送失败,dest_1=${lic_detalles.dest_1}, dest_2=${lic_detalles.dest_2},错误:${e.message}`);
  }
}

// 新增邮箱格式验证函数
function validateEmails(emailArray) {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return emailArray.filter(email => email && emailRegex.test(email.trim()));
}

// 统一日志记录函数
function logError(errorMsg) {
  var tiempo = Utilities.formatDate(new Date(), "GMT-5", "dd-MM-yyyy HH:mm:ss");
  var logSheet = SpreadsheetApp.getActive().getSheetByName('LOG');
  logSheet.appendRow([tiempo, errorMsg]);
  SpreadsheetApp.flush();
}

2. 给单行处理添加异常捕获(可选)

为避免单行数据格式错误导致整个循环终止,给主函数的循环内部套一层try-catch,仅终止当前行处理,不影响后续行:

function main_emailReminderAlert() {
  var sheet, logSheet;
  try {
    // 获取表格数据
    sheet = SpreadsheetApp.getActive().getSheetByName('BASE');
    logSheet = SpreadsheetApp.getActive().getSheetByName('LOG');
    var startRow = 2;
    var numRows = sheet.getLastRow() - 1;
    var numColumns = sheet.getLastColumn();
    var dataRange = sheet.getRange(startRow, 1, numRows, numColumns);
    var data = dataRange.getValues();

    for (var i = 0; i < data.length; ++i) {
      try { // 单行处理异常捕获
        var row = data[i];
        var fecha_act = new Date(),
            fecha_venc = row[12],
            numero = row[0],
            config = row[11],
            est_aviso1 = row[17],
            est_aviso2 = row[18],
            est_aviso3 = row[19],
            est_aviso4 = row[20],
            dest_1 = row[21],
            dest_2 = row[22],
            webhook = row[23];
        
        var lic_detalles = {
          numero: row[0],
          pais: row[1],
          marca: row[2],
          tecnologia: row[3],
          nombre_equipo: row[4],
          cliente: row[5],
          ip: row[6],
          modelo: row[7],
          serial_number: row[8],
          licencia: row[9],
          sm: row[10],
          config: row[11],
          est_aviso1: row[17],
          est_aviso2: row[18],
          est_aviso3: row[19],
          est_aviso4: row[20],
          dest_1: row[21],
          dest_2: row[22],
          webhook: row[23],
        };

        // 日期处理
        var t2 = new Date(fecha_venc);
        t2.setHours(0,0,0,0);
        var t1 = new Date(fecha_act);
        t1.setHours(0,0,0,0);
        var diferencia_ms = (t2.getTime() - t1.getTime());
        var dias_rest = (diferencia_ms/(24*3600*1000));
        lic_detalles.dias_rest = dias_rest;

        // 到期提醒逻辑
        if(config == "Activado"  ) {
          if(dias_rest>=0 && dias_rest<=5  && est_aviso4==false ) {
            console.log(`LA LICENCIA DE ${lic_detalles.cliente} VENCE EN 5 DIAS`);
            sendEmail(lic_detalles);
            notificaAlerta(lic_detalles);
            sheet.getRange(numero+1, 17).setValue(fecha_act);
            sheet.getRange(numero+1, 21).setValue(true);
          }
          else  if(dias_rest>=6 && dias_rest<=15   && est_aviso3==false){
            console.log(`LA LICENCIA DE ${lic_detalles.cliente} VENCE EN 15 DIAS`);
            sendEmail(lic_detalles);
            notificaAlerta(lic_detalles);
            sheet.getRange(numero+1, 16).setValue(fecha_act);
            sheet.getRange(numero+1, 20).setValue(true);
          }
          else  if (dias_rest>=16 && dias_rest<= 30  && est_aviso2== false  ) {
            console.log(`LA LICENCIA DE ${lic_detalles.cliente} VENCE EN 30 DIAS`);
            sendEmail(lic_detalles);
            notificaAlerta(lic_detalles);
            sheet.getRange(numero+1, 15).setValue(fecha_act);
            sheet.getRange(numero+1,19).setValue(true);
          }
          else if (dias_rest >= 31 && dias_rest <= 60  && est_aviso1== false) {
            console.log(`LA LICENCIA DE ${lic_detalles.cliente} VENCE EN 60 DIAS`);
            sendEmail(lic_detalles);
            notificaAlerta(lic_detalles);
            sheet.getRange(numero+1, 14).setValue(fecha_act);
            sheet.getRange(numero+1, 18).setValue(true);
          }
        }
      } catch(rowError) {
        var tiempo = Utilities.formatDate(new Date(), "GMT-5", "dd-MM-yyyy HH:mm:ss");
        logSheet.appendRow([tiempo, `行号${row[0]}处理失败:${rowError.message}`]);
        SpreadsheetApp.flush();
        notificaMonitoreo(`行号${row[0]}处理失败:${rowError.message}`, url_monitoreo_desarrollos);
      }
    }
  } catch(globalError) {
    var tiempo = Utilities.formatDate(new Date(), "GMT-5", "dd-MM-yyyy HH:mm:ss");
    logSheet.appendRow([tiempo, `全局错误:${globalError.message}`]);
    SpreadsheetApp.flush();
    notificaMonitoreo(`全局错误:${globalError.message}`, url_monitoreo_desarrollos);
  }
}

二、表单提交时反馈无效邮箱

1. 表单端实时验证(最简单)

打开关联的Google表单,找到邮箱输入字段,设置数据验证:

  • 选择「文本」→「匹配正则表达式」,输入邮箱正则^[^\s@]+@[^\s@]+\.[^\s@]+$
  • 设置提示文本,比如「请输入有效的邮箱地址」
    用户提交时输入无效邮箱,表单会直接阻止提交并提示。

2. 提交后发送反馈邮件

如果需要在提交后给用户发反馈(比如表单允许提交但后续邮件发送失败),添加onFormSubmit触发器:

function onFormSubmit(e) {
  const response = e.response;
  const respondentEmail = response.getRespondentEmail(); // 需要在表单设置里开启「收集回复者邮箱」
  const dest1 = e.values[21]; // 对应Sheet中dest_1列,注意索引从0开始,需根据实际列调整
  const dest2 = e.values[22]; // 对应dest_2列

  const validEmails = validateEmails([dest1, dest2]);
  if (validEmails.length === 0) {
    if (respondentEmail) {
      MailApp.sendEmail({
        to: respondentEmail,
        subject: "提交提醒:无效邮箱地址",
        body: `您提交的邮箱地址(${dest1}, ${dest2})无效,请重新提交正确的邮箱,以便接收许可证到期提醒。`
      });
    }
    logError(`表单提交无效邮箱:提交者=${respondentEmail}, dest1=${dest1}, dest2=${dest2}`);
  }
}

在脚本编辑器中设置触发器:选择onFormSubmit,事件类型为「表单提交」。

三、其他最佳实践

  • 邮箱去重:发送邮件时合并to和cc中的重复邮箱,避免用户收到多份相同邮件
  • 测试模式:添加开关变量const isTest = true;,测试时跳过MailApp.sendEmail,仅打印日志
  • Sheet数据验证:在BASE表的dest_1、dest_2列设置数据验证,强制输入有效邮箱,从源头上减少错误
  • 配额监控:关注MailApp每日发送配额(免费版100封/天),避免超出限制

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 20:54:22