与AWS Lambda中的电子邮件中退订链接
#aws #node #terraform #ses

🐙 GitHub

退订新闻通讯

您正在向用户发送电子邮件,但是不提供他们退订这些电子邮件的方法吗?让我很快向您展示如何添加订阅链接到Increaser新闻通讯,以便您立即执行此操作。

unsubscribing from Increaser news

在这个故事中,我们将在新闻通讯中添加一个链接,该链接将导致页面触发AWS Lambda负责取消用户的订阅。为了创建所有所需的基础架构,我们将使用Terraform。

退订链接

首先,我们将向电子邮件添加退订链接。下面示例的链接要求从Increaser新闻中退订给定的用户。

<a
  target="_blank"
  href="https://pomodoro-subscriber.increaser.org/pomodoro-news-email/{{id}}/unsubscribe"
  >unsubscribe</a
>

此链接导致AWS lambda将处理电子邮件订阅pomodoro-subscriber.increaser.org。该路线有三个部分:

  1. 电子邮件类型(Pomodoro-news-Email)
  2. 用户ID
  3. 行动(退订)

AWS Lambda

lambda.js,我们导出将处理传入请求的功能。它提取typeidaction我们在链接中指定并调用处理程序函数接收html。

如果出现问题,我们返回400。如果错误没有故意丢弃,我们将其报告给Sentry。

const Sentry =  require('@sentry/node')

const handler = require('./handler')
const { BadRequest } = require('./errors')

Sentry.init({ dsn: process.env.SENTRY_KEY })

exports.handler = async ({ path }, context, callback) => {
  try {
    const [type, id, action] = path.split('/').slice(1)
    const body = await handler(type, id, action)
    callback(null, {
      statusCode: 200,
      headers: {
        'Content-Type': 'text/html'
      },
      body
    })
  } catch (error) {
    const isBadRequest = error instanceof BadRequest
    if (!isBadRequest) {
      console.log(error)
      Sentry.withScope(scope => {
        scope.setExtra('path', path)
        Sentry.captureException(error)
      })
      await Sentry.flush(2000)
    }
    callback(null, {
      statusCode: 400,
      headers: {
        'Content-Type': 'text/html'
      },
      body: isBadRequest ? error.message : 'internal error'
    })
  }
}

实现处理程序功能,我们可以找到here。它检查请求是否有效,更新用户并返回适当的html。

基础设施

您可以在存储库here中找到与基础架构有关的所有内容。在其他故事中已经涵盖了非常相似的基础设施 - AWS for Website CI/CD with TerraformsAmazon DocumentDB and AWS Lambda with Terraform。因此,我们只会在这里介绍变量。

要创建基础架构,我们需要首先设置环境变量(AWS凭据)。

导出AWS_ACCESS_KEY_ID =
导出aws_secret_access_key =
导出aws_region =




In `vars.tf`, we specify all variables we need to create resources on AWS.



```hcl:title=vars.tf
variable "name" {
  default = "pomodoro-subscriber"
}

# OPTIONAL:

# if you use Sentry for errors reporting
variable "sentry_key" {}

// if you have a domain
variable "domain" {}
variable "zone_id" {}
variable "certificate_arn" {}


# if you want to use AWS CodePipeline for CD
variable "ci_container_name" {}
variable "repo_owner" {}
variable "repo_name" {}
variable "branch" {}

这里唯一需要的变量是我们将在几乎每个资源中使用的名称。

其他所有内容都是可选的,如果您使用的是Sentry,则可以指定sentry_key

如果您有注册域和证书,​​则可以为这些变量指定设置值:domainzone_idcertificate_arn

如果您喜欢将AWS Codepipeline用于CI/CD的想法,并将您的代码放在GitHub存储库中,并且在AWS ECS注册表中使用Docker容器,则还可以指定最后四个变量。另外,您需要将令牌设置为环境变量。得到很简单,您可以找到步骤there

导出github_to和=




To find more information about the CD part, you can check [this story](https://radzion.com/blog/aws-website/ci-cd).

We can specify variables by editing a file or by setting environment variables like this.



```shell{promptUser: ''}
export TF_VAR_name=<NAME_FOR_RESOURCES>
export TF_VAR_docdb_password=<PASSWORD_FOR_AMAZON_DOCUMENTDB>
export TF_VAR_certificate_arn=<YOUR_DOMAIN_SERTIFICATE_ARN>
export TF_VAR_zone_id=<YOUR_DOMAIN_ZONE_ID>
export TF_VAR_domain=<YOUR_DOMAIN>

现在让我们运行这两个命令来创建资源。

Terraform Init
Terraform应用




That’s it. The only thing left is to update the function name in [the deployment script](https://github.com/RodionChachura/email-unsubscribe-lambda/blob/master/lambda/management/deploy.sh#L8).