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
相关产品推荐
相关产品推荐

