SSMS运行SSIS包时Script Task发邮件偶发语法错误失败
问题根因
这个偶发语法错误和部署环境无关,核心是代码缺少输入合法性校验,触发条件完全依赖每次运行时从数据库读取的动态内容:
- 你开启了
mail.IsBodyHtml = true,但没有对从数据库读取的varEmailMessage原始内容做任何HTML转义处理。当查询到的新标签内容包含<、>、&、未闭合标签、特殊控制字符时,SMTP服务器解析HTML正文时就会抛出语法错误;内容无特殊字符时任务就正常运行,因此表现为时好时坏。 - 收件人、抄送人处理逻辑存在缺陷:仅支持英文分号分隔的地址列表,没有自动去除地址前后空格、过滤非法格式邮件地址的逻辑,一旦动态读取的收件人字段带全角分号、多余空格、非法格式地址,调用地址添加方法时也会触发语法类报错。
- 本地设计器运行正常是因为测试用的数据集刚好没有包含上述非法内容,调度作业运行时读取生产动态数据,碰到非法内容就会触发报错。
另外你代码中定义了MailFrom变量但未实际使用,发件人直接读取账号配置变量,属于冗余逻辑问题,虽然不会直接触发偶发报错,但可能导致发件人显示不符合预期。
修复方案
按以下步骤调整代码即可彻底解决问题:
- 首先给脚本任务添加
System.Web程序集引用,用于HTML内容转义。 - 补全正文内容转义逻辑:原始数据库内容先做HTML编码,再替换换行符为HTML换行标签,避免特殊字符破坏HTML结构。
- 优化收件人/抄送人处理逻辑:同时兼容分号、逗号两种常见分隔符,自动去除每个地址前后的空白字符,过滤空值和明显不符合格式的地址。
- 增强异常日志:catch块中记录完整异常堆栈和触发报错的上下文信息,方便后续快速定位问题。
- 修正发件人赋值逻辑,使用提前读取的
MailFrom变量作为发件人地址。
修复后的核心代码参考:
public void Main() { string MailTo = Dts.Variables["User::varSendMailTo"].Value.ToString().Trim(); string MailFrom = Dts.Variables["User::varSendMailFrom"].Value.ToString().Trim(); string MailCC = Dts.Variables["User::varSendMailCC"].Value.ToString().Trim(); string EmailMessage = Dts.Variables["User::varEmailMessage"].Value.ToString(); // 对原始内容做HTML转义,替换换行符为HTML换行标签 string MailBody = HttpUtility.HtmlEncode(EmailMessage).Replace("\n", "<br/>").Replace("\r", ""); EmailFunction(MailTo, MailFrom, MailBody, MailCC); Dts.TaskResult = (int)ScriptResults.Success; } public void EmailFunction(string MailTo, string MailFrom, string MailBody, string MailCC) { string username = Dts.Variables["$Package::strMailUserName"].Value.ToString().Trim(); string password = Dts.Variables["$Package::strMailPassWord"].Value.ToString().Trim(); string MailSub = "Production Missing Tags List for " + DateTime.Now.ToString("dd-MMM-yyyy"); SendEmail(username, password, MailFrom, MailTo, MailSub, MailBody, MailCC); } // 抽离公共的邮件地址解析方法 private List<string> ParseEmailList(string rawAddressStr) { List<string> addressList = new List<string>(); if (string.IsNullOrWhiteSpace(rawAddressStr)) return addressList; // 同时兼容分号、逗号、中文分号作为分隔符 string[] splitArr = rawAddressStr.Split(new char[] { ';', ',', ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (string addr in splitArr) { string cleanAddr = addr.Trim(); // 简单校验邮箱格式,过滤非法地址 if (!string.IsNullOrWhiteSpace(cleanAddr) && cleanAddr.Contains("@") && cleanAddr.Contains(".")) { addressList.Add(cleanAddr); } } return addressList; } public void SendEmail(string username, string password, string mailFrom, string EmailTo, string MailSub, string MailBod, string EmCC) { try { MailMessage mail = new MailMessage(); mail.From = new MailAddress(mailFrom); mail.Subject = MailSub; mail.Body = MailBod; mail.IsBodyHtml = true; // 批量处理收件人 List<string> toList = ParseEmailList(EmailTo); foreach (string addr in toList) { mail.To.Add(addr); } // 批量处理抄送人 List<string> ccList = ParseEmailList(EmCC); foreach (string addr in ccList) { mail.CC.Add(addr); } var client = new SmtpClient(Dts.Variables["$Package::strMailHost"].Value.ToString().Trim(), 587) { UseDefaultCredentials = false, Credentials = new NetworkCredential(username, password), EnableSsl = true }; client.Send(mail); } catch(Exception ex) { // 记录完整错误信息,方便排查 string errMsg = $"邮件发送失败,异常信息:{ex.ToString()},收件人:{EmailTo},正文片段:{MailBod.Substring(0, Math.Min(100, MailBod.Length))}"; Dts.Events.FireError(-1, "SendEmail Task", errMsg, "", -1); Dts.TaskResult = (int)ScriptResults.Failure; } }
验证方式
部署修复后的版本后,手动构造包含特殊HTML字符、全角分隔符、多余空格的测试数据跑批,确认任务可以正常发送邮件,不会再抛出语法错误即可。
内容的提问来源于stack exchange,提问作者Rajendra Gowd
相关产品推荐
相关产品推荐

