退订新闻通讯
您正在向用户发送电子邮件,但是不提供他们退订这些电子邮件的方法吗?让我很快向您展示如何添加订阅链接到Increaser新闻通讯,以便您立即执行此操作。
在这个故事中,我们将在新闻通讯中添加一个链接,该链接将导致页面触发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
。该路线有三个部分:
- 电子邮件类型(Pomodoro-news-Email)
- 用户ID
- 行动(退订)
AWS Lambda
从lambda.js
,我们导出将处理传入请求的功能。它提取type
,id
和action
我们在链接中指定并调用处理程序函数接收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 Terraforms和Amazon 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
。
如果您有注册域和证书,则可以为这些变量指定设置值:domain
,zone_id
和certificate_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).