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

如何配置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端口填22
    • SftpUserName:字符串类型,填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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 01:31:17