如何配置ETL Package实现Outlook附件自动上传至SFTP路径
前置准备
- 本文以最常用的SSIS(SQL Server Integration Services,可视化ETL Package开发工具,新手门槛最低)为例做配置,提前装好对应版本的SSDT开发环境即可
- 提前准备SFTP服务器连接信息:地址、端口、登录账号、密码、目标上传目录,先手动测试账号可正常登录、对目标目录有写入权限
- 运行ETL包的机器提前安装桌面版Outlook并配置好对应收信账号,包运行时Outlook可保持后台运行;如果要部署在无桌面环境的服务器,后续会提无Outlook依赖的替代方案
- 提前建本地临时附件存储目录,比如
D:\ETL_Temp\MailAttachments,给ETL运行账号开该目录的读写权限
完整配置流程
步骤1:创建ETL项目与全局配置变量
- 打开SSDT,新建Integration Services项目,命名为
OutlookAttachmentToSFTP - 在SSIS变量面板新建以下包级变量,后续改配置不用逐个改组件:
MailFilterSubject:字符串类型,值填要抓取的邮件主题关键词,比如*每日业务报表*,用通配符匹配目标邮件避免抓错LocalTempPath:字符串类型,值填之前建的本地临时目录,比如D:\ETL_Temp\MailAttachments\SftpHost:字符串类型,填SFTP服务器地址SftpPort:Int32类型,默认SFTP端口填22SftpUserName:字符串类型,填SFTP登录账号SftpPassword:字符串类型,填SFTP登录密码,把变量的Sensitive属性设为True避免明文泄露SftpRemotePath:字符串类型,填SFTP上的目标存储路径,比如/upload/business_report/
步骤2:配置Outlook邮件筛选与附件自动下载
注意:第一次运行脚本调用Outlook时,会弹出「程序正在尝试访问电子邮件信息」的安全提示,选允许访问最长时限即可,后续不会重复弹出。
- 在控制流拖入一个【脚本任务】,命名为
下载匹配邮件附件到本地临时目录,双击打开配置页,把MailFilterSubject、LocalTempPath两个变量加入ReadOnlyVariables列表 - 点击【编辑脚本】,在弹出的VSTA编辑器里用以下C#代码替换默认脚本内容:
using System; using System.IO; using Microsoft.Office.Interop.Outlook; using System.Runtime.InteropServices; public void Main() { string filterSubject = Dts.Variables["User::MailFilterSubject"].Value.ToString(); string savePath = Dts.Variables["User::LocalTempPath"].Value.ToString(); // 先清空临时目录旧文件,避免重复上传 if (Directory.Exists(savePath)) { Array.ForEach(Directory.GetFiles(savePath), File.Delete); } Application outlookApp = new Application(); NameSpace outlookNS = outlookApp.GetNamespace("MAPI"); MAPIFolder inbox = outlookNS.GetDefaultFolder(OlDefaultFolders.olFolderInbox); Items matchItems = inbox.Items.Restrict($"[Subject] like '{filterSubject}' AND [UnRead] = true"); // 只抓未读的匹配主题邮件,需要抓已读就去掉AND后面的条件 foreach (object item in matchItems) { if (item is MailItem mail) { foreach (Attachment att in mail.Attachments) { // 过滤邮件签名内嵌的小图片、表情资源,只抓正常业务附件 if (att.Size > 10240 && !att.FileName.StartsWith("image")) { string fullSavePath = Path.Combine(savePath, att.FileName); att.SaveAsFile(fullSavePath); } } mail.UnRead = false; // 抓完标记为已读,避免下次重复抓取 } Marshal.ReleaseComObject(item); } Marshal.ReleaseComObject(matchItems); Marshal.ReleaseComObject(inbox); Marshal.ReleaseComObject(outlookNS); Marshal.ReleaseComObject(outlookApp); Dts.TaskResult = (int)ScriptResults.Success; }
- 保存脚本关闭编辑器,这一步配置完成后,手动执行任务就能自动把符合规则的邮件附件存到本地临时目录。
步骤3:配置本地附件上传到SFTP指定目录
- 运行ETL包的机器提前安装WinSCP客户端,记住安装路径,默认路径为
C:\Program Files (x86)\WinSCP\WinSCP.exe,这个方案不用装额外SSIS插件,新手出错率最低 - 再拖一个【脚本任务】到控制流,命名为
上传临时目录文件到SFTP,把所有SFTP相关变量、本地临时路径变量加入ReadOnlyVariables列表 - 点击编辑脚本,用以下C#代码替换默认内容:
using System; using System.Diagnostics; using System.IO; public void Main() { string winSCPExePath = @"C:\Program Files (x86)\WinSCP\WinSCP.exe"; string localPath = Dts.Variables["User::LocalTempPath"].Value.ToString(); string sftpHost = Dts.Variables["User::SftpHost"].Value.ToString(); int sftpPort = (int)Dts.Variables["User::SftpPort"].Value; string sftpUser = Dts.Variables["User::SftpUserName"].Value.ToString(); string sftpPwd = Dts.Variables["User::SftpPassword"].Value.ToString(); string sftpRemote = Dts.Variables["User::SftpRemotePath"].Value.ToString(); // 生成临时上传脚本 string scriptPath = Path.Combine(localPath, "sftp_upload_script.txt"); string logPath = Path.Combine(localPath, "sftp_upload.log"); File.WriteAllText(scriptPath, $"open sftp://{sftpUser}:{sftpPwd}@{sftpHost}:{sftpPort}/ -hostkey=*" + Environment.NewLine + $"cd {sftpRemote}" + Environment.NewLine + $"put {localPath}*" + Environment.NewLine + "exit"); // 执行上传命令 ProcessStartInfo psi = new ProcessStartInfo(); psi.FileName = winSCPExePath; psi.Arguments = $"/script=\"{scriptPath}\" /log=\"{logPath}\""; psi.UseShellExecute = false; psi.CreateNoWindow = true; Process uploadProc = Process.Start(psi); uploadProc.WaitForExit(); // 校验上传结果 if (uploadProc.ExitCode == 0) { File.Delete(scriptPath); Dts.TaskResult = (int)ScriptResults.Success; } else { Dts.Events.FireError(0, "SFTP上传失败", $"错误详情查看日志:{logPath}", "", 0); Dts.TaskResult = (int)ScriptResults.Failure; } }
注:代码里
-hostkey=*是新手配置阶段跳过主机密钥校验的写法,正式生产环境建议替换成SFTP服务器实际的主机密钥串,避免连接安全风险。
- 保存脚本关闭编辑器,用成功连线把「下载附件」和「上传SFTP」两个脚本任务连起来,代表先执行下载、下载成功再执行上传。
步骤4:配置定时调度与异常告警
- 需要定时自动执行的话,在SQL Server代理新建作业,把这个SSIS包加为作业步骤,设置需要的执行频率即可,比如每1小时执行一次、工作日早8点执行
- 可以额外加一个【发送邮件任务】,把两个脚本任务的失败分支连线到该任务,配置成任务执行失败时自动发告警邮件,不用人工盯运行状态
- 第一次上线前先手动调试执行全流程,确认附件能正常下载、能准确传到SFTP指定目录,再开启定时调度
新手常见踩坑点
- 不要在装了32位Office/WinSCP的环境下把包的运行平台设为64位,会报组件找不到错误,在项目属性-调试页把
Run64BitRuntime的值改成和安装软件匹配的位数即可 - Linux系统的SFTP路径区分大小写,提前手动登录确认路径存在,不要写错目录名
- 本地临时目录不要设在系统盘有权限限制的路径,比如
C:\根目录、Program Files目录下,容易出现权限不足无法保存附件的问题 - 如果不想依赖本地Outlook客户端,可以把第一步的收信逻辑换成IMAP协议实现,不用装Outlook也能抓附件,适合无桌面环境的服务器部署
内容的提问来源于stack exchange,提问作者Priyanka Anjuri
相关产品推荐
相关产品推荐

