从 Snowflake 发送电子邮件警报

2023-12-11

如果 Snowflake 中的存储过程失败,我们有什么方法可以发送电子邮件警报吗? 当我检查 Snowflake 文档时,Snowflake 中没有提到电子邮件实用程序


您可以直接从 Snowflake 发送电子邮件,也可以选择将表/视图中的数据作为附件发送。这是使用 Snowflake 外部函数完成的,该函数又通过 AWS Gateway 调用 AWS Lambda 函数。 第一步是设置 AWS 网关。您可以按照以下说明操作:在 AWS 上创建可自定义的外部函数

如果您从 Snowflake 获得了示例函数,那么您就已经成功地为添加电子邮件功能奠定了基础。接下来是设置 S3 存储桶来创建需要作为电子邮件附件发送的数据文件。

  1. 创建一个名为“snowapi”的 AWS S3 存储桶。我们不需要将此存储桶暴露给互联网,因此请将“阻止所有公共访问”设置为“开”。

  2. 现在您需要向 Snowflake 提供对此存储桶的访问权限。创建 IAM 用户“snowflake”。添加权限 -> 附加现有策略:AmazonS3FullAccess。转到“安全凭证”选项卡和“创建访问密钥”。使用以下命令中的访问密钥 ID 和秘密访问密钥将数据卸载到 S3 存储桶中。

    创建或替换 UTIL.AWS_S3_STAGE URL='s3://snowapi/' 凭证=(AWS_KEY_ID='ABCD123456789123456789' AWS_SECRET_KEY='ABCD12345678901234567890123456789');

    复制到 @UTIL.AWS_S3_STAGE/outbound/SampleData.csv 从 文件格式= 覆盖=真 单=真;

  3. 下一步是使用下面的 Nodejs 代码创建一个新的 Lambda 函数。请注意,这使用发送网格API。 Sendgrid 拥有永久免费套餐,每天可发送 100 封电子邮件。我在本地安装了这个库并且上传了 zip 文件文件发送到 AWS 以创建 Lambda 函数。

//Lambda Function name: email
const sgMail = require('@sendgrid/mail');
var AWS = require('aws-sdk');
var s3 = new AWS.S3();
 
exports.handler =  async (event, context, callback) => {
  sgMail.setApiKey(process.env.SENDGRID_KEY);
 
  const paramArray = JSON.parse(event.body).data[0];
  //paramArray[0] has the row number from Snowflake
  var message = {
        to: paramArray[1].replace(/\s/g, '').split(','),
        from: paramArray[2].replace(/\s/g, ''),
        subject: paramArray[3],
        html: paramArray[4]
      };
  
  // Attach file
  if (paramArray.length > 5) {
    var fileName = paramArray[5].substring(paramArray[5].lastIndexOf("/")+1);
    var filePath = paramArray[5].substring(0, paramArray[5].lastIndexOf("/"));
    try {
      const params = {Bucket: process.env.BUCKET_NAME + filePath, Key: fileName};
      const data = await s3.getObject(params).promise();
      var fileContent = data.Body.toString('base64');
    } catch (e) {
      throw new Error(`Could not retrieve file from S3: ${e.message}`);
    }
    message.attachments = [{content: fileContent,
                            filename: fileName,
                            type: "application/text",
                            disposition: "attachment"
                          }];
  }
    
  try{
      await sgMail.send(message);
      return {
          'statusCode': 200,
          'headers': { 'Content-Type': 'application/json' },
          'body' : "{'data': [[0, 'Email Sent to "+ paramArray[1] + "']]}" 
      };
    } catch(e){
      return {
          'statusCode': 202,
          'headers': { 'Content-Type': 'application/json' },
          'body' : "{'data': [[0, 'Error - " + e.message + "']]}" 
      };
    } 
 
};
  1. 为 Lambda 函数设置以下两个环境变量:

     SENDGRID_KEY: <sendgrid_api_key>
     BUCKET_NAME: snowapi
    
  2. 创建雪花外部函数:

     create or replace external function util.aws_email
     (mailTo varchar,mailFrom varchar,subject varchar,htmlBody varchar,fileName varchar)
     returns variant
     api_integration = aws_api_integration
     as 'https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/PROD/email';
    
  3. 为上述外部函数创建一个包装程序:

     create or replace procedure util.sendemail
     (MAILTO varchar,MAILFROM varchar,SUBJECT  varchar,HTMLBODY varchar,FILENAME varchar)
     returns string
     language javascript
     EXECUTE AS OWNER
     as
     $$
       // Call the AWSLambda function.
       var qry = "select util.aws_email(:1,:2,:3,:4,:5)"; 
    
       // null should be in lowercase. 
       var stmt = snowflake.createStatement({sqlText: qry, 
                                             binds: [MAILTO,
                                                     MAILFROM||'[email protected]',
                                                     SUBJECT ||'Email sent from Snowflake',
                                                     HTMLBODY||'<p>Hi there,</p> <p>Good luck!</p>',
                                                     FILENAME||null]
                                           });
       var rs;
       try{
           rs = stmt.execute();
           rs.next();
           return rs.getColumnValue(1);
       }
       catch(err) {
         throw "ERROR: " + err.message.replace(/\n/g, " ");
       }
     $$;
    
  4. 可以了,好了!最终结果是一个干净的调用,发送如下电子邮件。

     Call SENDEMAIL('[email protected], [email protected]',
                     '[email protected]', 
                     'Test Subject',
                     'Sample Body');
    

祝你好运!!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从 Snowflake 发送电子邮件警报 的相关文章

随机推荐

  • 如何为 IE、Firefox 和 Chrome 编写网络浏览器插件

    我需要编写一个支持 IE 7 Firefox 3 Chrome 的网络浏览器插件 该插件必须能够将 DirectX 对象放置在网页中 我没有使用插件的经验 我做了一些调查并决定使用 FireBreath 来实现 我无法理解如何将图像放置在插
  • 如何在 D3js 中动态添加图像到圆圈

    我很难弄清楚如何使用数据集中的链接将图像放置在圆圈内 我知道需要一种模式才能将图像添加到节点 related关于此主题的 SO 问题在介绍节点和数据之前附加了定义 图案和图像元素 就我而言 我找不到在选择器函数内附加标签的方法 因为数据是动
  • 如何覆盖testNG中的index.html报告

    我有一个场景 需要将一些自定义消息添加到 index html testNG 报告中 有什么办法可以做到这一点吗 我刚刚创建了一个自定义注释 我想像 DataProvider 一样将其发布到 index html testNG 报告中 到目
  • 将 ImageView 放在布局中的 ImageView 上 [关闭]

    Closed 这个问题需要多问focused 目前不接受答案 我创建了一个 Android 应用程序 我想将 ImageView 放在 ImageView 上 如何让我成为可能 Thanks 我已经为你创建了代码 请看这是 XML 代码
  • f2py:包装 fortran 模块,该模块利用分布在不同文件中的子例程?

    由于我描述的原因earlier 我需要在Python中使用LAPACKs dgesvd和zgesvd方法 而不是包装在numpy中的方法 有人指出 我可以使用 f2py 来创建我自己的 python 包 问题是 lapack 中的 dges
  • 重写函数类型原型

    我在玩耍并试图覆盖时遇到了一个有趣的行为Function原型 假设我们已经像这样重写了 toString const funcToString Function prototype toString Function prototype t
  • 清理 Oracle 序列

    我广泛使用 SQL Server 但对 Oracle 的经验很少 我接到的任务是 清理 Oracle 数据库中的序列 但我不知道如何安全地完成此任务 我需要确定表中实际的最大值 假设 ID 105 然后查看该 ID 的下一个序列是什么 如果
  • fontello 中的图标字体不适用于 Meteor js

    我已经从 fontello 下载了自定义图标字体 并打算在我的流星应用程序中使用它 我尝试了下载包附带的演示 字体显示正常 这是我的CSS font face font family fontello src url fonts fonte
  • iOS 应用程序:几次崩溃,常见主题为:SIGSEGV 和 _sigtramp

    作为 obj c 的新手 我不擅长阅读堆栈跟踪 但我通常可以找出代码中从哪里开始查找 然而 在测试过程中 其中一位测试人员不断报告多次随机崩溃 我无法确定堆栈跟踪的头或尾 因为它们不指向我自己的任何代码 这里有两个 0 WIT Free 0
  • 如何在 Swift 中将枚举和 switch() 与 UITableViewController 结合使用

    我的 UITableView 有两个部分 所以我为它们创建了一个枚举 private enum TableSections HorizontalSection VerticalSection 如何使用在 numberOfRowsInSect
  • Android Automotive Arm_86 未在虚拟设备中列出

    我一直在开发 Android 汽车应用程序 但由于未知原因尚未设置模拟器 我已经尝试过文档并且this我正在使用金丝雀频道 下载汽车图像后 它没有列在虚拟设备下 我使用的是android studio 4 0 1版本 如何解决这个问题 谢谢
  • 如何在网站上添加实时代码编辑器? [关闭]

    Closed 这个问题需要细节或清晰度 目前不接受答案 我正在创建一个需要实时编辑代码 Java c python javascript 等 的网站 我知道 codemirror 我想知道如何在网站上运行代码 例如 W3Schools 自己
  • 矢量 a 、矢量 a[n] 和矢量 a(n) 之间有什么区别?

    我刚刚了解了向量 但对它们的用途感到困惑 请告诉我以下之间有什么区别 vector
  • 存储过程插入两个有关系的表?

    我试图将新行插入两个有关系的表中 我写的存储过程如下 ALTER PROCEDURE InsertUserProfile UserID varchar 10 Pass varchar 50 Enabled int Permission in
  • 集群模式路由网格不工作,默认情况下像主机模式一样工作

    描述 Swarm 模式路由网格不起作用 而是像默认情况下使用主机模式一样工作 我们部署了由 3 个主节点和 8 个工作节点组成的集群 每个节点都位于云服务的不同实例中开放堆栈使用 Terraform 和 Ansible 群和路由网格工作完美
  • 合并两个表格轨道

    基本上我有同样的问题 比如 user1224344 如何从 Rails 中的同一页面提交多个重复的表单 最好使用一个按钮 第一个答案看起来相当不错 但作为 Rails 初学者 我在将其移植到我的项目中时遇到问题 好的 我有两个具有相同控制器
  • 如何检查用户是否正在刷新页面或导航到其他页面

    场景 每当用户离开页面时 我想在本地存储中设置一些变量 Using window onbeforeunload我收到用户即将离开页面的事件 但我想在用户刷新时设置不同的变量值以及不同的页面导航 var someVar when refres
  • 如何将我的类隐式转换为另一种类型?

    例如隐式地 MyClass myClass new MyClass int i myClass 您需要在MyClass file public static implicit operator int MyClass instance if
  • 向自定义策略添加限制并使声明可选 Azure B2C

    我正在尝试使用 LocalAccountSignUpWithLogonName 自定义策略收集用户详细信息 我已添加
  • 从 Snowflake 发送电子邮件警报

    如果 Snowflake 中的存储过程失败 我们有什么方法可以发送电子邮件警报吗 当我检查 Snowflake 文档时 Snowflake 中没有提到电子邮件实用程序 您可以直接从 Snowflake 发送电子邮件 也可以选择将表 视图中的